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)
26 //#define UFO_DEBUG_WRITE_MAIN_IMAGE
27 //#define UFO_DEBUG_WRITE_DEBUG_IMAGE
30 #define UFO_DEBUG_STARTUP_TIMES
31 //#define UFO_DEBUG_FATAL_ABORT
32 #define UFO_DEBUG_DEBUG /* ;-) */
33 //#define UFO_TRACE_VM_DOER
34 //#define UFO_TRACE_VM_RUN
35 //#define UFO_DEBUG_INCLUDE
36 //#define UFO_DEBUG_DUMP_NEW_HEADERS
37 //#define UFO_DEBUG_FIND_WORD
38 //#define UFO_DEBUG_FIND_WORD_IN_VOC
39 //#define UFO_DEBUG_FIND_WORD_COLON
41 // 2/8 msecs w/o inlining
42 // 1/5 msecs with inlining
44 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
46 # define UFO_FORCE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
48 #define UFO_DISABLE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
50 // detect arch, and use faster memory access code on x86
51 #if defined(__x86_64__) || defined(_M_X64) || \
52 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
53 # define UFO_FAST_MEM_ACCESS
56 // should not be bigger than this!
57 #define UFO_MAX_WORD_LENGTH (250)
59 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
62 // ////////////////////////////////////////////////////////////////////////// //
63 static void ufoFlushOutput (void);
65 UFO_DISABLE_INLINE
const char *ufo_assert_failure (const char *cond
, const char *fname
,
66 int fline
, const char *func
)
68 for (const char *t
= fname
; *t
; ++t
) {
70 if (*t
== '/' || *t
== '\\') fname
= t
+1;
72 if (*t
== '/') fname
= t
+1;
76 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
81 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
84 static char ufoRealPathBuf
[32769];
85 static char ufoRealPathHashBuf
[32769];
88 //==========================================================================
92 //==========================================================================
93 static char *ufoRealPath (const char *fname
) {
95 if (fname
!= NULL
&& fname
[0] != 0) {
96 res
= realpath(fname
, NULL
);
98 const size_t slen
= strlen(res
);
100 strcpy(ufoRealPathBuf
, res
);
102 res
= ufoRealPathBuf
;
116 static time_t secstart
= 0;
121 //==========================================================================
125 //==========================================================================
126 static uint64_t ufo_get_msecs (void) {
128 return GetTickCount();
131 #ifdef CLOCK_MONOTONIC
132 ufo_assert(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
134 // this should be available everywhere
135 ufo_assert(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
139 secstart
= ts
.tv_sec
+1;
140 ufo_assert(secstart
); // it should not be zero
142 return (uint64_t)(ts
.tv_sec
-secstart
+2)*1000U+(uint32_t)ts
.tv_nsec
/1000000U;
144 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
149 //==========================================================================
153 //==========================================================================
154 UFO_FORCE_INLINE
uint32_t joaatHashBuf (const void *buf
, size_t len
, uint8_t orbyte
) {
155 uint32_t hash
= 0x29a;
156 const uint8_t *s
= (const uint8_t *)buf
;
158 hash
+= (*s
++)|orbyte
;
170 // this converts ASCII capitals to locase (and destroys other, but who cares)
171 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
174 //==========================================================================
178 //==========================================================================
179 UFO_FORCE_INLINE
char toUpper (char ch
) {
180 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
184 //==========================================================================
188 //==========================================================================
189 UFO_FORCE_INLINE
uint8_t toUpperU8 (uint8_t ch
) {
190 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
194 //==========================================================================
198 //==========================================================================
199 UFO_FORCE_INLINE
int digitInBase (char ch
, int base
) {
201 case '0' ... '9': ch
= ch
- '0'; break;
202 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
203 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
204 default: base
= -1; break;
206 return (ch
>= 0 && ch
< base
? ch
: -1);
211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
212 ;; word header format:
213 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
214 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
215 ;; exact uppercase, only something that resembles it)
216 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
217 ;; before nfa, we have such "hidden" fields:
218 ;; dd xfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
219 ;; dd yfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
220 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
221 ;; ; if there is no hashtable, this field is not used
223 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
224 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
226 ;; dd flags-and-name-len ; see below
227 ;; db name ; no terminating zero or other "termination flag" here
228 ;; here could be some 0 bytes to align everything to 4 bytes
229 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
230 ;; ; full length, including padding, but not including this byte
232 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
236 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
241 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
250 ;; bit 6: *UNUSED* main scattered colon word (with "...")
253 ;; argtype is the type of the argument that this word reads from the threaded code.
254 ;; possible argument types:
257 ;; 2: cell-size numeric literal
258 ;; 3: cell-counted string with terminating zero (not counted)
259 ;; 4: cfa of another word
262 ;; 7: byte-counted string with terminating zero (not counted)
263 ;; 8: data skip: the arg is amout of bytes to skip (not including the counter itself)
266 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
267 ;; wordlist structure (at PFA)
268 ;; -4: wordlist type id (used by structs, for example)
270 ;; dd voclink (voclink always points here)
271 ;; dd parent (if not zero, all parent words are visible)
272 ;; dd header-nfa (can be 0 for anonymous wordlists)
273 ;; hashtable (if enabled), or ~0U if no hash table
277 // ////////////////////////////////////////////////////////////////////////// //
278 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
279 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
280 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
281 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
282 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
283 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
284 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
285 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
286 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
287 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
288 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
289 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
290 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
291 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
292 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
293 #define UFO_XFA_TO_WST(xfa_) ((xfa_) - 4u)
294 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 2u * 4u)
295 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
298 // ////////////////////////////////////////////////////////////////////////// //
299 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
300 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
301 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
302 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
303 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
305 #define UFO_HASHTABLE_SIZE (256)
307 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
309 #define UFO_MAX_NATIVE_CFAS (1024u)
310 static ufoNativeCFA
*ufoForthCFAs
= NULL
;
311 static uint32_t ufoCFAsUsed
= 0;
313 static uint32_t ufoDoForthCFA
;
314 static uint32_t ufoDoVariableCFA
;
315 static uint32_t ufoDoValueCFA
;
316 static uint32_t ufoDoConstCFA
;
317 static uint32_t ufoDoDeferCFA
;
318 static uint32_t ufoDoVocCFA
;
319 static uint32_t ufoDoCreateCFA
;
320 static uint32_t ufoDoUserVariableCFA
;
322 static uint32_t ufoLitStr8CFA
;
324 // special address types:
325 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
326 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
328 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
329 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
330 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
331 #define UFO_ADDR_HANDLE_SHIFT (12)
332 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
334 // temporary area is 1MB buffer out of the main image
335 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
336 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
338 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
341 static uint32_t *ufoImage
= NULL
;
342 static uint32_t ufoImageSize
= 0;
344 static uint8_t *ufoDebugImage
= NULL
;
345 static uint32_t ufoDebugImageUsed
= 0; // in bytes
346 static uint32_t ufoDebugImageSize
= 0; // in bytes
347 static uint32_t ufoDebugFileNameHash
= 0; // current file name hash
348 static uint32_t ufoDebugFileNameLen
= 0; // current file name length
349 static uint32_t ufoDebugLastLine
= 0;
350 static uint32_t ufoDebugLastLinePCOfs
= 0;
351 static uint32_t ufoDebugLastLineDP
= 0;
352 static uint32_t ufoDebugCurrDP
= 0;
354 static uint32_t ufoInRunWord
= 0;
356 static volatile int ufoVMAbort
= 0;
357 static volatile int ufoVMStop
= 0;
359 #define ufoTrueValue (~(uint32_t)0)
363 UFO_MODE_NATIVE
= 0, // executing forth code
364 UFO_MODE_MACRO
= 1, // executing forth asm macro
366 static uint32_t ufoMode
= UFO_MODE_NONE
;
368 #define UFO_DSTACK_SIZE (8192)
369 #define UFO_RSTACK_SIZE (4096)
370 #define UFO_LSTACK_SIZE (4096)
371 #define UFO_MAX_TASK_NAME (127)
372 #define UFO_VOCSTACK_SIZE (16u)
374 // to support multitasking (required for the debugger),
375 // our virtual machine state is encapsulated in a struct.
376 typedef struct UfoState_t
{
378 uint32_t dStack
[UFO_DSTACK_SIZE
];
379 uint32_t rStack
[UFO_RSTACK_SIZE
];
380 uint32_t lStack
[UFO_LSTACK_SIZE
];
381 uint32_t IP
; // in image
382 uint32_t SP
; // points AFTER the last value pushed
383 uint32_t RP
; // points AFTER the last value pushed
384 uint32_t RPTop
; // stop when RP is this
392 uint32_t vocStack
[UFO_VOCSTACK_SIZE
]; // cfas
396 uint32_t imageTempSize
;
397 // linked list of all allocated states (tasks)
398 char name
[UFO_MAX_TASK_NAME
+ 1];
402 #define UFO_MAX_STATES (8192)
404 // this is indexed by id
405 static UfoState
*ufoStateMap
[UFO_MAX_STATES
] = {NULL
};
406 static uint32_t ufoStateUsedBitmap
[UFO_MAX_STATES
/32] = {0};
408 // currently active execution state
409 static UfoState
*ufoCurrState
= NULL
;
410 // state we're yielded from
411 static UfoState
*ufoYieldedState
= NULL
;
412 // if debug state is not NULL, VM will switch to it
413 // after executing one instruction from the current state.
414 // it will store current state in `ufoDebugeeState`.
415 static UfoState
*ufoDebuggerState
= NULL
;
416 static uint32_t ufoSingleStep
= 0;
418 #define ufoDStack (ufoCurrState->dStack)
419 #define ufoRStack (ufoCurrState->rStack)
420 #define ufoLStack (ufoCurrState->lStack)
421 #define ufoIP (ufoCurrState->IP)
422 #define ufoSP (ufoCurrState->SP)
423 #define ufoRP (ufoCurrState->RP)
424 #define ufoRPTop (ufoCurrState->RPTop)
425 #define ufoLP (ufoCurrState->LP)
426 #define ufoLBP (ufoCurrState->LBP)
427 #define ufoRegA (ufoCurrState->regA)
428 #define ufoImageTemp (ufoCurrState->imageTemp)
429 #define ufoImageTempSize (ufoCurrState->imageTempSize)
430 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
431 #define ufoVocStack (ufoCurrState->vocStack)
432 #define ufoVSP (ufoCurrState->VSP)
434 // 256 bytes for user variables
435 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
436 #define UFO_USER_AREA_SIZE (256u)
437 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
438 #define UFO_NBUF_SIZE (256u)
439 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
440 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
442 // dynamically allocated text input buffer
443 // always ends with zero (this is word name too)
444 static const uint32_t ufoAddrTIBx
= UFO_ADDR_TEMP_BIT
+ 0u * 4u; // TIB
445 static const uint32_t ufoAddrINx
= UFO_ADDR_TEMP_BIT
+ 1u * 4u; // >IN
446 static const uint32_t ufoAddrDefTIB
= UFO_ADDR_TEMP_BIT
+ 2u * 4u; // default TIB (handle); user cannot change it
447 static const uint32_t ufoAddrBASE
= UFO_ADDR_TEMP_BIT
+ 3u * 4u;
448 static const uint32_t ufoAddrSTATE
= UFO_ADDR_TEMP_BIT
+ 4u * 4u;
449 static const uint32_t ufoAddrContext
= UFO_ADDR_TEMP_BIT
+ 5u * 4u; // CONTEXT
450 static const uint32_t ufoAddrCurrent
= UFO_ADDR_TEMP_BIT
+ 6u * 4u; // CURRENT (definitions will go there)
451 static const uint32_t ufoAddrSelf
= UFO_ADDR_TEMP_BIT
+ 7u * 4u; // CURRENT (definitions will go there)
452 static const uint32_t ufoAddrInterNextLine
= UFO_ADDR_TEMP_BIT
+ 8u * 4u; // (INTERPRET-NEXT-LINE)
453 static const uint32_t ufoAddrEP
= UFO_ADDR_TEMP_BIT
+ 9u * 4u; // (EP) -- exception frame pointer
454 static const uint32_t ufoAddrUserVarUsed
= UFO_ADDR_TEMP_BIT
+ 10u * 4u;
456 static uint32_t ufoAddrVocLink
;
457 static uint32_t ufoAddrDP
;
458 static uint32_t ufoAddrDPTemp
;
459 static uint32_t ufoAddrNewWordFlags
;
460 static uint32_t ufoAddrRedefineWarning
;
461 static uint32_t ufoAddrLastXFA
;
463 static uint32_t ufoForthVocId
;
464 static uint32_t ufoCompilerVocId
;
465 static uint32_t ufoInterpNextLineCFA
;
467 // allows to redefine even protected words
468 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
469 // do not warn about ordinary words, allow others
470 #define UFO_REDEF_WARN_NONE (0)
471 // do warn (or fail on protected)
472 #define UFO_REDEF_WARN_NORMAL (1)
473 // do warn (or fail on protected) for parent dicts too
474 #define UFO_REDEF_WARN_PARENTS (2)
476 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
477 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
479 #define UFO_MAX_NESTED_INCLUDES (32)
486 uint32_t id
; // non-zero unique id
489 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
490 static uint32_t ufoFileStackPos
; // after the last used item
492 static FILE *ufoInFile
= NULL
;
493 static uint32_t ufoInFileNameLen
= 0;
494 static uint32_t ufoInFileNameHash
= 0;
495 static char *ufoInFileName
= NULL
;
496 static char *ufoLastIncPath
= NULL
;
497 static char *ufoLastSysIncPath
= NULL
;
498 static int ufoInFileLine
= 0;
499 static uint32_t ufoFileId
= 0;
500 static uint32_t ufoLastUsedFileId
= 0;
501 static int ufoLastEmitWasCR
= 1;
503 // dynamic memory handles
504 typedef struct UHandleInfo_t
{
511 struct UHandleInfo_t
*next
;
514 static UfoHandle
*ufoHandleFreeList
= NULL
;
515 static UfoHandle
**ufoHandles
= NULL
;
516 static uint32_t ufoHandlesUsed
= 0;
517 static uint32_t ufoHandlesAlloted
= 0;
519 #define UFO_HANDLE_FREE (~(uint32_t)0)
521 static char ufoCurrFileLine
[520];
524 static uint32_t ufoInBacktrace
= 0;
527 // ////////////////////////////////////////////////////////////////////////// //
528 static void ufoClearCondDefines (void);
530 static void ufoRunVMCFA (uint32_t cfa
);
532 static void ufoBacktrace (uint32_t ip
, int showDataStack
);
534 static void ufoClearCondDefines (void);
536 static UfoState
*ufoNewState (void);
537 static void ufoInitStateUserVars (UfoState
*st
, uint32_t cfa
);
538 static void ufoFreeState (UfoState
*st
);
539 static UfoState
*ufoFindState (uint32_t stid
);
540 static void ufoSwitchToState (UfoState
*newst
);
542 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
545 static void ufoDisableRaw (void);
546 static void ufoTTYRawFlush (void);
548 static int ufoIsGoodTTY (void);
550 #ifdef UFO_DEBUG_DEBUG
551 static void ufoDumpDebugImage (void);
555 // ////////////////////////////////////////////////////////////////////////// //
556 #define UFWORD(name_) \
557 static void ufoWord_##name_ (uint32_t mypfa)
559 #define UFCALL(name_) ufoWord_##name_(0)
560 #define UFCFA(name_) (&ufoWord_##name_)
563 UFWORD(CPEEK_REGA_IDX
);
564 UFWORD(CPOKE_REGA_IDX
);
567 UFWORD(PAR_HANDLE_LOAD_BYTE
);
568 UFWORD(PAR_HANDLE_LOAD_WORD
);
569 UFWORD(PAR_HANDLE_LOAD_CELL
);
570 UFWORD(PAR_HANDLE_STORE_BYTE
);
571 UFWORD(PAR_HANDLE_STORE_WORD
);
572 UFWORD(PAR_HANDLE_STORE_CELL
);
575 //==========================================================================
579 //==========================================================================
580 static void ufoFlushOutput (void) {
588 //==========================================================================
592 // if `reuse` is not 0, reuse/free `fname`
594 //==========================================================================
595 static void ufoSetInFileNameEx (const char *fname
, int reuse
) {
596 ufo_assert(fname
== NULL
|| (fname
!= ufoInFileName
));
597 if (fname
== NULL
|| fname
[0] == 0) {
598 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
599 ufoInFileNameLen
= 0;
600 ufoInFileNameHash
= 0;
601 if (reuse
&& fname
!= NULL
) free((void *)fname
);
603 const uint32_t fnlen
= (uint32_t)strlen(fname
);
604 const uint32_t fnhash
= joaatHashBuf(fname
, fnlen
, 0);
605 if (ufoInFileNameLen
!= fnlen
|| ufoInFileNameHash
!= fnhash
) {
606 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
608 ufoInFileName
= (char *)fname
;
610 ufoInFileName
= strdup(fname
);
611 if (ufoInFileName
== NULL
) ufoFatal("out of memory for filename info");
613 ufoInFileNameLen
= fnlen
;
614 ufoInFileNameHash
= fnhash
;
616 if (reuse
&& fname
!= NULL
) free((void *)fname
);
622 //==========================================================================
626 //==========================================================================
627 UFO_FORCE_INLINE
void ufoSetInFileName (const char *fname
) {
628 ufoSetInFileNameEx(fname
, 0);
632 //==========================================================================
634 // ufoSetInFileNameReuse
636 //==========================================================================
637 UFO_FORCE_INLINE
void ufoSetInFileNameReuse (const char *fname
) {
638 ufoSetInFileNameEx(fname
, 1);
642 //==========================================================================
646 //==========================================================================
647 void ufoSetUserAbort (void) {
652 //==========================================================================
656 //==========================================================================
657 static UfoHandle
*ufoAllocHandle (uint32_t typeid) {
658 ufo_assert(typeid != UFO_HANDLE_FREE
);
659 UfoHandle
*newh
= ufoHandleFreeList
;
661 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
662 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
663 // due to offsets, this is the maximum number of handles we can have
664 if (newsz
> 0x1ffffU
) {
665 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
666 newsz
= 0x1ffffU
+ 1U;
667 ufo_assert(newsz
> ufoHandlesAlloted
);
669 UfoHandle
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
670 if (nh
== NULL
) ufoFatal("out of memory for handle table");
672 ufoHandlesAlloted
= newsz
;
674 newh
= calloc(1, sizeof(UfoHandle
));
675 if (newh
== NULL
) ufoFatal("out of memory for handle info");
676 ufoHandles
[ufoHandlesUsed
] = newh
;
677 // setup new handle info
678 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
681 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
682 ufoHandleFreeList
= newh
->next
;
684 // setup new handle info
685 newh
->typeid = typeid;
694 //==========================================================================
698 //==========================================================================
699 static void ufoFreeHandle (UfoHandle
*hh
) {
701 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
702 if (hh
->data
) free(hh
->data
);
703 hh
->typeid = UFO_HANDLE_FREE
;
707 hh
->next
= ufoHandleFreeList
;
708 ufoHandleFreeList
= hh
;
713 //==========================================================================
717 //==========================================================================
718 static UfoHandle
*ufoGetHandle (uint32_t hh
) {
720 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
721 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
722 if (hh
< ufoHandlesUsed
) {
723 res
= ufoHandles
[hh
];
724 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
735 //==========================================================================
739 //==========================================================================
740 static void setLastIncPath (const char *fname
, int system
) {
741 if (fname
== NULL
|| fname
[0] == 0) {
743 if (ufoLastSysIncPath
) free(ufoLastIncPath
);
744 ufoLastSysIncPath
= NULL
;
746 if (ufoLastIncPath
) free(ufoLastIncPath
);
747 ufoLastIncPath
= strdup(".");
753 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
754 ufoLastSysIncPath
= strdup(fname
);
755 lslash
= ufoLastSysIncPath
;
756 cpos
= ufoLastSysIncPath
;
758 if (ufoLastIncPath
) free(ufoLastIncPath
);
759 ufoLastIncPath
= strdup(fname
);
760 lslash
= ufoLastIncPath
;
761 cpos
= ufoLastIncPath
;
765 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
767 if (*cpos
== '/') lslash
= cpos
;
776 //==========================================================================
778 // ufoClearIncludePath
780 // required for UrAsm
782 //==========================================================================
783 void ufoClearIncludePath (void) {
784 if (ufoLastIncPath
!= NULL
) {
785 free(ufoLastIncPath
);
786 ufoLastIncPath
= NULL
;
788 if (ufoLastSysIncPath
!= NULL
) {
789 free(ufoLastSysIncPath
);
790 ufoLastSysIncPath
= NULL
;
795 //==========================================================================
799 //==========================================================================
800 static void ufoErrorPrintFile (FILE *fo
, const char *errwarn
) {
801 if (ufoInFileName
!= NULL
) {
802 fprintf(fo
, "UFO %s at file %s, line %d: ", errwarn
, ufoInFileName
, ufoInFileLine
);
804 fprintf(fo
, "UFO %s somewhere in time: ", errwarn
);
809 //==========================================================================
813 //==========================================================================
814 static void ufoErrorMsgV (const char *errwarn
, const char *fmt
, va_list ap
) {
816 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
817 ufoErrorPrintFile(stderr
, errwarn
);
818 vfprintf(stderr
, fmt
, ap
);
825 //==========================================================================
829 //==========================================================================
830 __attribute__((format(printf
, 1, 2)))
831 void ufoWarning (const char *fmt
, ...) {
834 ufoErrorMsgV("WARNING", fmt
, ap
);
838 //==========================================================================
842 //==========================================================================
843 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
844 void ufoFatal (const char *fmt
, ...) {
850 ufoErrorMsgV("ERROR", fmt
, ap
);
851 if (!ufoInBacktrace
) {
853 ufoBacktrace(ufoIP
, 1);
856 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
859 #ifdef UFO_DEBUG_FATAL_ABORT
870 // ////////////////////////////////////////////////////////////////////////// //
871 // working with the stacks
872 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
873 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); --ufoSP
; }
874 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
875 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
876 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
877 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
878 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
; }
879 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
; }
880 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
; }
882 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
883 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
884 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
); }
885 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
; }
887 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
888 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); --ufoRP
; }
889 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
890 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
891 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
893 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
896 //==========================================================================
900 //==========================================================================
901 static void ufoImgEnsureSize (uint32_t addr
) {
902 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
903 if (addr
>= ufoImageSize
) {
904 // 64MB should be enough for everyone!
905 if (addr
>= 0x04000000U
) {
906 ufoFatal("image grown too big (addr=0%08XH)", addr
);
908 const const uint32_t osz
= ufoImageSize
;
910 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
911 ufo_assert(nsz
> addr
);
912 uint32_t *nimg
= realloc(ufoImage
, nsz
);
914 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
915 ufoImageSize
/ 1024u / 1024u,
916 nsz
/ 1024u / 1024u);
920 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
925 //==========================================================================
929 //==========================================================================
930 static void ufoImgEnsureTemp (uint32_t addr
) {
931 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
932 if (addr
>= ufoImageTempSize
) {
933 if (addr
>= 1024u * 1024u) {
934 ufoFatal("Forth segmentation fault at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
936 const uint32_t osz
= ufoImageTempSize
;
938 const uint32_t nsz
= (addr
|0x00001fffU
) + 1U;
939 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
941 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
942 ufoImageTempSize
/ 1024u,
946 ufoImageTempSize
= nsz
;
947 memset((char *)ufoImageTemp
+ osz
, 0, (nsz
- osz
));
952 #ifdef UFO_FAST_MEM_ACCESS
953 //==========================================================================
959 //==========================================================================
960 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
961 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
962 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
963 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
964 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
965 addr
&= UFO_ADDR_TEMP_MASK
;
966 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
967 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
969 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
974 //==========================================================================
980 //==========================================================================
981 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
982 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
983 if (addr
+ 1u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 1u);
984 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
985 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
986 addr
&= UFO_ADDR_TEMP_MASK
;
987 if (addr
+ 1u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 1u);
988 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
990 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
995 //==========================================================================
1001 //==========================================================================
1002 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1003 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1004 if (addr
+ 3u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 3u);
1005 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
1006 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1007 addr
&= UFO_ADDR_TEMP_MASK
;
1008 if (addr
+ 3u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 3u);
1009 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
1011 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1016 //==========================================================================
1022 //==========================================================================
1023 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1024 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1025 if (addr
>= ufoImageSize
) {
1026 // accessing unallocated image area is segmentation fault
1027 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1029 return *((const uint8_t *)ufoImage
+ addr
);
1030 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1031 addr
&= UFO_ADDR_TEMP_MASK
;
1032 if (addr
>= ufoImageTempSize
) {
1033 // accessing unallocated image area is segmentation fault
1034 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1036 return *((const uint8_t *)ufoImageTemp
+ addr
);
1038 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1043 //==========================================================================
1049 //==========================================================================
1050 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1051 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1052 if (addr
+ 1u >= ufoImageSize
) {
1053 // accessing unallocated image area is segmentation fault
1054 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1056 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
1057 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1058 addr
&= UFO_ADDR_TEMP_MASK
;
1059 if (addr
+ 1u >= ufoImageTempSize
) {
1060 // accessing unallocated image area is segmentation fault
1061 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1063 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1065 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1070 //==========================================================================
1076 //==========================================================================
1077 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1078 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1079 if (addr
+ 3u >= ufoImageSize
) {
1080 // accessing unallocated image area is segmentation fault
1081 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1083 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
1084 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1085 addr
&= UFO_ADDR_TEMP_MASK
;
1086 if (addr
+ 3u >= ufoImageTempSize
) {
1087 // accessing unallocated image area is segmentation fault
1088 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1090 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1092 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1098 //==========================================================================
1104 //==========================================================================
1105 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1107 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1108 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
1109 imgptr
= &ufoImage
[addr
/4u];
1110 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1111 addr
&= UFO_ADDR_TEMP_MASK
;
1112 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
1113 imgptr
= &ufoImageTemp
[addr
/4u];
1115 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1117 const uint8_t val
= (uint8_t)value
;
1118 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1122 //==========================================================================
1128 //==========================================================================
1129 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1130 ufoImgPutU8(addr
, value
&0xffU
);
1131 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1135 //==========================================================================
1141 //==========================================================================
1142 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1143 ufoImgPutU16(addr
, value
&0xffffU
);
1144 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1148 //==========================================================================
1154 //==========================================================================
1155 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1157 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1158 if (addr
>= ufoImageSize
) return 0;
1159 imgptr
= &ufoImage
[addr
/4u];
1160 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1161 addr
&= UFO_ADDR_TEMP_MASK
;
1162 if (addr
>= ufoImageTempSize
) return 0;
1163 imgptr
= &ufoImageTemp
[addr
/4u];
1165 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1168 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1169 return (uint32_t)val
;
1173 //==========================================================================
1179 //==========================================================================
1180 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1181 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1185 //==========================================================================
1191 //==========================================================================
1192 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1193 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1198 //==========================================================================
1200 // ufoEnsureDebugSize
1202 //==========================================================================
1203 UFO_DISABLE_INLINE
void ufoEnsureDebugSize (uint32_t sdelta
) {
1204 ufo_assert(sdelta
!= 0);
1205 if (ufoDebugImageSize
!= 0) {
1206 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1207 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1208 // grow by 32KB, this should be more than enough
1209 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0x7fffU
) + 1u;
1210 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1211 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1212 ufoDebugImage
= ndb
;
1213 ufoDebugImageSize
= newsz
;
1216 // initial allocation: 32KB, quite a lot
1217 ufo_assert(ufoDebugImage
== NULL
);
1218 ufo_assert(ufoDebugImageUsed
== 0);
1219 ufoDebugImageSize
= 1024 * 32;
1220 ufoDebugImage
= malloc(ufoDebugImageSize
);
1221 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1226 #define UFO_DBG_PUT_U4(val_) do { \
1227 const uint32_t vv_ = (val_); \
1228 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1229 ufoDebugImageUsed += 4u; \
1236 ...first line info header...
1237 line info header (or reset):
1238 db 0 ; zero line delta
1239 dw followFileInfoSize ; either it, or 0 if reused
1240 dd fileInfoOfs ; present only if reused
1248 dd nameLen ; without terminating 0
1249 ...name... (0-terminated)
1251 we will never compare file names: length and hash should provide
1252 good enough unique identifier.
1254 static uint8_t *ufoDebugImage = NULL;
1255 static uint32_t ufoDebugImageUsed = 0; // in bytes
1256 static uint32_t ufoDebugImageSize = 0; // in bytes
1257 static uint32_t ufoDebugFileNameHash = 0; // current file name hash
1258 static uint32_t ufoDebugFileNameLen = 0; // current file name length
1259 static uint32_t ufoDebugCurrDP = 0;
1263 //==========================================================================
1265 // ufoSkipDebugVarInt
1267 //==========================================================================
1268 static __attribute__((unused
)) uint32_t ufoSkipDebugVarInt (uint32_t ofs
) {
1271 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1272 byte
= ufoDebugImage
[ofs
]; ofs
+= 1u;
1273 } while (byte
>= 0x80);
1278 //==========================================================================
1280 // ufoCalcDebugVarIntSize
1282 //==========================================================================
1283 UFO_FORCE_INLINE
uint8_t ufoCalcDebugVarIntSize (uint32_t v
) {
1293 //==========================================================================
1295 // ufoGetDebugVarInt
1297 //==========================================================================
1298 static __attribute__((unused
)) uint32_t ufoGetDebugVarInt (uint32_t ofs
) {
1303 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1304 byte
= ufoDebugImage
[ofs
];
1305 v
|= (uint32_t)(byte
& 0x7f) << shift
;
1310 } while (byte
>= 0x80);
1315 //==========================================================================
1317 // ufoPutDebugVarInt
1319 //==========================================================================
1320 UFO_FORCE_INLINE
void ufoPutDebugVarInt (uint32_t v
) {
1321 ufoEnsureDebugSize(5u); // maximum size
1324 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)(v
| 0x80u
);
1326 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)v
;
1328 ufoDebugImageUsed
+= 1;
1334 #ifdef UFO_DEBUG_DEBUG
1335 //==========================================================================
1339 //==========================================================================
1340 static void ufoDumpDebugImage (void) {
1342 uint32_t dbgpos
= 4u; // first line header info
1343 uint32_t lastline
= 0;
1344 uint32_t lastdp
= 0;
1345 while (dbgpos
< ufoDebugImageUsed
) {
1346 if (ufoDebugImage
[dbgpos
] == 0) {
1348 dbgpos
+= 1u; // skip flag
1349 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1350 lastdp
= ufoGetDebugVarInt(dbgpos
);
1351 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1352 if (fhdrSize
== 0) {
1354 const uint32_t infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1355 fprintf(stderr
, "*** OLD FILE: %s\n", (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u));
1356 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2]);
1357 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1]);
1360 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
+ 3u * 4u));
1361 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[2]);
1362 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[1]);
1365 fprintf(stderr
, "LINES-OFS: 0x%08x (hsz: %u -- 0x%08x)\n", dbgpos
, fhdrSize
, fhdrSize
);
1366 lastline
= ~(uint32_t)0;
1368 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1369 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1370 ufo_assert(ln
!= 0);
1372 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1373 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1375 fprintf(stderr
, " line %6u: edp=%u\n", lastline
, lastdp
);
1383 //==========================================================================
1385 // ufoRecordDebugCheckFile
1387 // if we moved to the new file:
1388 // put "line info header"
1389 // put new file info (or reuse old)
1391 //==========================================================================
1392 UFO_FORCE_INLINE
void ufoRecordDebugCheckFile (void) {
1393 if (ufoDebugImageUsed
== 0 ||
1394 ufoDebugFileNameLen
!= ufoInFileNameLen
||
1395 ufoDebugFileNameHash
!= ufoInFileNameHash
)
1397 // new file record (or reuse old one)
1398 const int initial
= (ufoDebugImageUsed
== 0);
1399 uint32_t fileRec
= 0;
1400 // try to find and old one
1402 fileRec
= *(const uint32_t *)ufoDebugImage
;
1404 fprintf(stderr
, "*** NEW-FILE(%u): 0x%08x: <%s> (frec=0x%08x)\n", ufoInFileNameLen
,
1405 ufoInFileNameHash
, ufoInFileName
, fileRec
);
1407 while (fileRec
!= 0 &&
1408 (ufoInFileNameLen
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1] ||
1409 ufoInFileNameHash
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]))
1412 fprintf(stderr
, "*** FRCHECK: 0x%08x\n", fileRec
);
1413 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1414 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1415 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1416 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1418 fileRec
= *(const uint32_t *)(ufoDebugImage
+ fileRec
);
1421 fprintf(stderr
, "*** FRCHECK-DONE: 0x%08x\n", fileRec
);
1423 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1424 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1425 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1426 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1430 ufoEnsureDebugSize(8u);
1431 *(uint32_t *)ufoDebugImage
= 0;
1433 // write "line info header"
1435 ufoEnsureDebugSize(32u);
1436 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1437 // file record size: 0 (reused)
1438 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = 0; ufoDebugImageUsed
+= 2u;
1440 ufoPutDebugVarInt(ufoDebugCurrDP
);
1442 UFO_DBG_PUT_U4(fileRec
);
1444 // name, trailing 0 byte, 3 dword fields
1445 const uint32_t finfoSize
= ufoInFileNameLen
+ 1u + 3u * 4u;
1446 ufo_assert(finfoSize
< 65536u);
1447 ufoEnsureDebugSize(finfoSize
+ 32u);
1449 *(uint32_t *)ufoDebugImage
= 0;
1450 ufoDebugImageUsed
= 4;
1452 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1454 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = (uint16_t)finfoSize
; ufoDebugImageUsed
+= 2u;
1456 ufoPutDebugVarInt(ufoDebugCurrDP
);
1457 // file record follows
1458 // fix file info offsets
1459 uint32_t lastOfs
= *(const uint32_t *)ufoDebugImage
;
1460 *(uint32_t *)ufoDebugImage
= ufoDebugImageUsed
;
1461 UFO_DBG_PUT_U4(lastOfs
);
1462 // save file info hash
1463 UFO_DBG_PUT_U4(ufoInFileNameHash
);
1464 // save file info length
1465 UFO_DBG_PUT_U4(ufoInFileNameLen
);
1467 if (ufoInFileNameLen
!= 0) {
1468 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, ufoInFileNameLen
+ 1u);
1469 ufoDebugImageUsed
+= ufoInFileNameLen
+ 1u;
1471 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u;
1474 ufoDebugFileNameLen
= ufoInFileNameLen
;
1475 ufoDebugFileNameHash
= ufoInFileNameHash
;
1476 ufoDebugLastLine
= ~(uint32_t)0;
1477 ufoDebugLastLinePCOfs
= 0;
1478 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1483 //==========================================================================
1485 // ufoRecordDebugRecordLine
1487 //==========================================================================
1488 UFO_FORCE_INLINE
void ufoRecordDebugRecordLine (uint32_t line
, uint32_t newhere
) {
1489 if (line
== ufoDebugLastLine
) {
1490 ufo_assert(ufoDebugLastLinePCOfs
!= 0);
1491 ufoDebugImageUsed
= ufoDebugLastLinePCOfs
;
1494 fprintf(stderr
, "FL-NEW-LINE(0x%08x): <%s>; new line: %u (old: %u)\n",
1496 ufoInFileName
, line
, ufoDebugLastLine
);
1498 ufoPutDebugVarInt(line
- ufoDebugLastLine
);
1499 ufoDebugLastLinePCOfs
= ufoDebugImageUsed
;
1500 ufoDebugLastLine
= line
;
1501 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1503 ufoPutDebugVarInt(newhere
- ufoDebugLastLineDP
);
1504 ufoDebugCurrDP
= newhere
;
1508 //==========================================================================
1512 //==========================================================================
1513 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1514 if (newhere
> ufoDebugCurrDP
) {
1515 uint32_t ln
= (uint32_t)ufoInFileLine
;
1516 if (ln
== ~(uint32_t)0) ln
= 0;
1518 fprintf(stderr
, "FL: <%s>; line: %d\n", ufoInFileName
, ufoInFileLine
);
1520 ufoRecordDebugCheckFile();
1521 ufoRecordDebugRecordLine(ln
, newhere
);
1526 //==========================================================================
1528 // ufoGetWordEndAddrYFA
1530 //==========================================================================
1531 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1533 const uint32_t oyfa
= yfa
;
1534 yfa
= ufoImgGetU32(yfa
);
1536 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1538 if ((yfa
& UFO_ADDR_TEMP_BIT
) != 0) {
1539 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1542 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1545 yfa
= UFO_YFA_TO_WST(yfa
);
1554 //==========================================================================
1556 // ufoGetWordEndAddr
1558 //==========================================================================
1559 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1561 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa
)));
1568 //==========================================================================
1574 // WARNING: this is SLOW!
1576 //==========================================================================
1577 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1580 //fprintf(stderr, "ufoFindWordForIP:000: ip=0x%08x\n", ip);
1581 // iterate over all words
1582 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1583 //fprintf(stderr, "ufoFindWordForIP:001: xfa=0x%08x\n", xfa);
1585 while (res
== 0 && xfa
!= 0) {
1586 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1587 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1588 //fprintf(stderr, "ufoFindWordForIP:002: yfa=0x%08x; wst=0x%08x\n", yfa, wst);
1589 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1590 if (ip
>= wst
&& ip
< wend
) {
1591 res
= UFO_YFA_TO_NFA(yfa
);
1593 xfa
= ufoImgGetU32(xfa
);
1602 //==========================================================================
1606 // return file name or `NULL`
1608 // WARNING: this is SLOW!
1610 //==========================================================================
1611 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
,
1612 uint32_t *nlen
, uint32_t *nhash
)
1614 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1615 const char *filename
= NULL
;
1616 uint32_t dbgpos
= 4u; // first line header info
1617 uint32_t lastline
= 0;
1618 uint32_t lastdp
= 0;
1619 uint32_t namelen
= 0;
1620 uint32_t namehash
= 0;
1621 while (dbgpos
< ufoDebugImageUsed
) {
1622 if (ufoDebugImage
[dbgpos
] == 0) {
1624 dbgpos
+= 1u; // skip flag
1625 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1626 lastdp
= ufoGetDebugVarInt(dbgpos
);
1627 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1629 if (fhdrSize
== 0) {
1631 infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1636 filename
= (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u);
1637 namelen
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2];
1638 namehash
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1];
1639 if (filename
[0] == 0) filename
= NULL
;
1641 lastline
= ~(uint32_t)0;
1643 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1644 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1645 ufo_assert(ln
!= 0);
1647 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1648 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1649 if (ip
>= lastdp
&& ip
< lastdp
+ edp
) {
1650 if (line
) *line
= lastline
;
1651 if (nlen
) *nlen
= namelen
;
1652 if (nhash
) *nhash
= namehash
;
1659 if (line
) *line
= 0;
1660 if (nlen
) *nlen
= 0;
1661 if (nhash
) *nlen
= 0;
1666 //==========================================================================
1670 //==========================================================================
1671 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1672 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
1674 dp
= ufoImgGetU32(ufoAddrDP
);
1675 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1677 ufoImgPutU32(ufoAddrDP
, dp
);
1679 dp
= ufoImgGetU32(ufoAddrDPTemp
);
1680 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1682 ufoImgPutU32(ufoAddrDPTemp
, dp
);
1687 //==========================================================================
1691 //==========================================================================
1692 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1693 ufoImgPutU8(UFO_GET_DP(), value
);
1698 //==========================================================================
1702 //==========================================================================
1703 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1704 ufoImgPutU32(UFO_GET_DP(), value
);
1709 #ifdef UFO_FAST_MEM_ACCESS
1711 //==========================================================================
1713 // ufoImgEmitU32_NoInline
1717 //==========================================================================
1718 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1719 ufoImgPutU32(UFO_GET_DP(), value
);
1725 //==========================================================================
1727 // ufoImgEmitU32_NoInline
1731 //==========================================================================
1732 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1733 ufoImgPutU32(UFO_GET_DP(), value
);
1740 //==========================================================================
1744 // this understands handle addresses
1746 //==========================================================================
1747 UFO_FORCE_INLINE
uint32_t ufoImgGetU8Ext (uint32_t addr
) {
1748 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1749 return ufoImgGetU8(addr
);
1753 UFCALL(PAR_HANDLE_LOAD_BYTE
);
1759 //==========================================================================
1763 // this understands handle addresses
1765 //==========================================================================
1766 UFO_FORCE_INLINE
void ufoImgPutU8Ext (uint32_t addr
, uint32_t value
) {
1767 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1768 ufoImgPutU8(addr
, value
);
1773 UFCALL(PAR_HANDLE_STORE_BYTE
);
1778 //==========================================================================
1782 //==========================================================================
1783 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
1784 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1788 //==========================================================================
1792 //==========================================================================
1793 UFO_FORCE_INLINE
void ufoResetTib (void) {
1794 uint32_t defTIB
= ufoImgGetU32(ufoAddrDefTIB
);
1795 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1797 // create new TIB handle
1798 UfoHandle
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
1799 defTIB
= tibh
->ufoHandle
;
1800 ufoImgPutU32(ufoAddrDefTIB
, defTIB
);
1802 if ((defTIB
& UFO_ADDR_HANDLE_BIT
) != 0) {
1803 UfoHandle
*hh
= ufoGetHandle(defTIB
);
1804 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
1805 if (hh
->size
== 0) {
1806 ufo_assert(hh
->data
== NULL
);
1807 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
1808 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
1809 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
1812 const uint32_t oldA
= ufoRegA
;
1813 ufoImgPutU32(ufoAddrTIBx
, defTIB
);
1814 ufoImgPutU32(ufoAddrINx
, 0);
1816 ufoPush(0); // value
1817 ufoPush(0); // offset
1818 UFCALL(CPOKE_REGA_IDX
);
1823 //==========================================================================
1827 //==========================================================================
1828 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
1829 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1830 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1831 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1832 if ((tib
& UFO_ADDR_HANDLE_BIT
) != 0) {
1833 UfoHandle
*hh
= ufoGetHandle(tib
);
1835 ufoFatal("cannot resize TIB, TIB is not a handle");
1837 if (hh
->size
< size
) {
1838 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
1839 uint8_t *nx
= realloc(hh
->data
, newsz
);
1840 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
1847 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib
);
1853 //==========================================================================
1857 //==========================================================================
1859 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1860 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1861 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1862 ufoFatal("cannot query TIB, TIB is not a handle");
1864 UfoHandle *hh = ufoGetHandle(tib);
1866 ufoFatal("cannot query TIB, TIB is not a handle");
1873 //==========================================================================
1877 //==========================================================================
1878 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
1879 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
1883 //==========================================================================
1887 //==========================================================================
1888 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
1889 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1890 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1891 return (uint8_t)ufoImgGetU8Ext(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
1898 //==========================================================================
1902 //==========================================================================
1903 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
1904 const uint32_t oldA
= ufoRegA
;
1905 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
1907 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
1908 UFCALL(CPOKE_REGA_IDX
);
1913 //==========================================================================
1917 //==========================================================================
1918 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
1919 const uint8_t ch
= ufoTibPeekCh();
1920 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
1925 //==========================================================================
1929 //==========================================================================
1930 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
1931 (void)ufoTibGetCh();
1935 // ////////////////////////////////////////////////////////////////////////// //
1936 // native CFA implementations
1939 //==========================================================================
1943 //==========================================================================
1944 static void ufoDoForth (uint32_t pfa
) {
1950 //==========================================================================
1954 //==========================================================================
1955 static void ufoDoVariable (uint32_t pfa
) {
1960 //==========================================================================
1962 // ufoDoUserVariable
1964 //==========================================================================
1965 static void ufoDoUserVariable (uint32_t pfa
) {
1966 ufoPush(ufoImgGetU32(pfa
));
1970 //==========================================================================
1974 //==========================================================================
1975 static void ufoDoValue (uint32_t pfa
) {
1976 ufoPush(ufoImgGetU32(pfa
));
1980 //==========================================================================
1984 //==========================================================================
1985 static void ufoDoConst (uint32_t pfa
) {
1986 ufoPush(ufoImgGetU32(pfa
));
1990 //==========================================================================
1994 //==========================================================================
1995 static void ufoDoDefer (uint32_t pfa
) {
1996 const uint32_t cfa
= ufoImgGetU32(pfa
);
2004 //==========================================================================
2008 //==========================================================================
2009 static void ufoDoVoc (uint32_t pfa
) {
2010 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
2014 //==========================================================================
2018 //==========================================================================
2019 static void ufoDoCreate (uint32_t pfa
) {
2024 //==========================================================================
2028 // this also increments last used file id
2030 //==========================================================================
2031 static void ufoPushInFile (void) {
2032 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
2033 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2034 stk
->fl
= ufoInFile
;
2035 stk
->fname
= ufoInFileName
;
2036 stk
->fline
= ufoInFileLine
;
2037 stk
->id
= ufoFileId
;
2038 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
2039 stk
->sysincpath
= (ufoLastSysIncPath
? strdup(ufoLastSysIncPath
) : NULL
);
2040 ufoFileStackPos
+= 1;
2042 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
2044 ufoLastUsedFileId
+= 1;
2045 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
2046 //ufoLastIncPath = NULL;
2050 //==========================================================================
2052 // ufoWipeIncludeStack
2054 //==========================================================================
2055 static void ufoWipeIncludeStack (void) {
2056 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2057 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2058 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2059 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2060 while (ufoFileStackPos
!= 0) {
2061 ufoFileStackPos
-= 1;
2062 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2063 if (stk
->fl
) fclose(stk
->fl
);
2064 if (stk
->fname
) free(stk
->fname
);
2065 if (stk
->incpath
) free(stk
->incpath
);
2070 //==========================================================================
2074 //==========================================================================
2075 static void ufoPopInFile (void) {
2076 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
2077 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2078 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2079 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2080 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2081 ufoFileStackPos
-= 1;
2082 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2083 ufoInFile
= stk
->fl
;
2084 ufoSetInFileNameReuse(stk
->fname
);
2085 ufoInFileLine
= stk
->fline
;
2086 ufoLastIncPath
= stk
->incpath
;
2087 ufoLastSysIncPath
= stk
->sysincpath
;
2088 ufoFileId
= stk
->id
;
2090 #ifdef UFO_DEBUG_INCLUDE
2091 if (ufoInFileName
== NULL
) {
2092 fprintf(stderr
, "INC-POP: no more files.\n");
2094 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
2100 //==========================================================================
2104 //==========================================================================
2105 void ufoDeinit (void) {
2106 #ifdef UFO_DEBUG_WRITE_MAIN_IMAGE
2108 FILE *fo
= fopen("zufo_main.img", "w");
2109 uint32_t dpTemp
= ufoImgGetU32(ufoAddrDPTemp
);
2110 uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2111 if ((dpMain
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) dpMain
= ufoImageSize
;
2112 if (dpTemp
!= 0 && (dpTemp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
2113 if (dpTemp
> dpMain
) dpMain
= dpTemp
;
2115 fwrite(ufoImage
, dpMain
, 1, fo
);
2120 #ifdef UFO_DEBUG_WRITE_DEBUG_IMAGE
2122 FILE *fo
= fopen("zufo_debug.img", "w");
2123 fwrite(ufoDebugImage
, ufoDebugImageUsed
, 1, fo
);
2128 #ifdef UFO_DEBUG_DEBUG
2130 uint32_t dpTemp
= ufoImgGetU32(ufoAddrDPTemp
);
2131 uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2132 if ((dpMain
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) dpMain
= ufoImageSize
;
2133 if (dpTemp
!= 0 && (dpTemp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
2134 if (dpTemp
> dpMain
) dpMain
= dpTemp
;
2136 fprintf(stderr
, "UFO: image used: %u; size: %u\n",
2137 dpMain
, ufoImageSize
);
2138 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n",
2139 ufoDebugImageUsed
, ufoDebugImageSize
);
2140 ufoDumpDebugImage();
2145 ufoCurrState
= NULL
;
2146 ufoYieldedState
= NULL
;
2147 ufoDebuggerState
= NULL
;
2148 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
2149 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
2151 uint32_t stid
= fidx
* 32u;
2153 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
2154 stid
+= 1u; bmp
>>= 1;
2159 free(ufoDebugImage
);
2160 ufoDebugImage
= NULL
;
2161 ufoDebugImageUsed
= 0;
2162 ufoDebugImageSize
= 0;
2163 ufoDebugFileNameHash
= 0;
2164 ufoDebugFileNameLen
= 0;
2165 ufoDebugLastLine
= 0;
2166 ufoDebugLastLinePCOfs
= 0;
2167 ufoDebugLastLineDP
= 0;
2171 ufoClearCondDefines();
2172 ufoWipeIncludeStack();
2174 // release all includes
2176 if (ufoInFileName
) free(ufoInFileName
);
2177 if (ufoLastIncPath
) free(ufoLastIncPath
);
2178 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
2179 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
2180 ufoInFileNameHash
= 0; ufoInFileNameLen
= 0;
2184 ufoForthCFAs
= NULL
;
2191 ufoMode
= UFO_MODE_NATIVE
;
2192 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
2196 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
2197 UfoHandle
*hh
= ufoHandles
[f
];
2199 if (hh
->data
!= NULL
) free(hh
->data
);
2203 if (ufoHandles
!= NULL
) free(ufoHandles
);
2204 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
2205 ufoHandleFreeList
= NULL
;
2207 ufoLastEmitWasCR
= 1;
2209 ufoClearCondDefines();
2213 //==========================================================================
2215 // ufoDumpWordHeader
2217 //==========================================================================
2218 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
2219 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
2221 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
2222 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
2223 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
2224 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
2225 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
2226 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
2227 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
2228 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
2229 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
2230 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
2231 const uint32_t nlen
= ufoImgGetU8(nfa
);
2232 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
2233 const uint32_t flags
= ufoImgGetU32(nfa
);
2234 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
2235 if ((flags
& 0xffff0000U
) != 0) {
2236 fprintf(stderr
, " FLAGS:");
2237 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
2238 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
2239 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
2240 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
2241 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
2242 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
2243 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
2244 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
2245 fputc('\n', stderr
);
2247 if ((flags
& 0xff00U
) != 0) {
2248 fprintf(stderr
, " ARGS: ");
2249 switch (flags
& UFW_WARG_MASK
) {
2250 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
2251 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
2252 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
2253 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
2254 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
2255 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
2256 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
2257 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
2258 case UFW_WARG_DATASKIP
: fprintf(stderr
, "DATA"); break;
2259 default: fprintf(stderr
, "wtf?!"); break;
2261 fputc('\n', stderr
);
2263 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
2264 fprintf(stderr
, " NAME(%u): ", nlen
);
2265 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2266 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2267 if (ch
<= 32 || ch
>= 127) {
2268 fprintf(stderr
, "\\x%02x", ch
);
2270 fprintf(stderr
, "%c", (char)ch
);
2273 fprintf(stderr
, "\n");
2274 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
2279 //==========================================================================
2285 //==========================================================================
2286 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
2290 #ifdef UFO_DEBUG_FIND_WORD
2291 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
2292 (unsigned) wnlen
, (const char *)wname
,
2293 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
2294 ufoDumpWordHeader(lfa
);
2296 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
2297 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
2298 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
2299 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
2301 const uint32_t nlen
= lenflags
&0xffU
;
2302 if (nlen
== wnlen
) {
2303 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
2305 while (pos
< nlen
) {
2306 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
2307 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
2308 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
2309 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
2310 if (c0
!= c1
) break;
2316 res
= UFO_ALIGN4(naddr
);
2325 //==========================================================================
2331 //==========================================================================
2332 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2333 uint32_t vocid
, int allowvochid
)
2336 if (wname
== NULL
) ufo_assert(wnlen
== 0);
2337 if (wnlen
!= 0 && vocid
!= 0) {
2338 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2339 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2340 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
2341 (unsigned) wnlen
, (const char *)wname
,
2342 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
2344 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
2345 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
2346 // hash table present, use it
2347 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2348 bfa
= ufoImgGetU32(bfa
);
2349 while (res
== 0 && bfa
!= 0) {
2350 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2351 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
2353 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
2354 bfa
= ufoImgGetU32(bfa
);
2357 // no hash table, use linear search
2358 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
2359 lfa
= ufoImgGetU32(lfa
);
2360 while (res
== 0 && lfa
!= 0) {
2361 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
2362 lfa
= ufoImgGetU32(lfa
);
2370 //==========================================================================
2374 // return part after the colon, or `NULL`
2376 //==========================================================================
2377 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
2378 const void *res
= NULL
;
2380 ufo_assert(wname
!= NULL
);
2381 const char *str
= (const char *)wname
;
2382 while (wnlen
!= 0 && str
[0] != ':') {
2383 str
+= 1; wnlen
-= 1;
2386 res
= (const void *)(str
+ 1); // skip colon
2393 //==========================================================================
2395 // ufoFindWordInVocAndParents
2397 //==========================================================================
2398 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2399 uint32_t vocid
, int allowvochid
)
2402 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2403 while (res
== 0 && vocid
!= 0) {
2404 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2405 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2411 //==========================================================================
2413 // ufoFindWordNameRes
2415 // find with name resolution
2419 //==========================================================================
2420 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2422 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2423 ufo_assert(wname
!= NULL
);
2425 const void *stx
= wname
;
2426 wname
= ufoFindColon(wname
, wnlen
);
2427 if (wname
!= NULL
) {
2428 // look in all vocabs (excluding hidden ones)
2429 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2430 ufo_assert(xlen
> 0 && xlen
< 255);
2431 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2432 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2433 #ifdef UFO_DEBUG_FIND_WORD_COLON
2434 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2435 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2437 while (res
== 0 && voclink
!= 0) {
2438 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2439 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2441 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2443 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2446 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2447 ufo_assert(voclink
!= 0);
2449 #ifdef UFO_DEBUG_FIND_WORD_COLON
2450 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2451 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2453 while (res
!= 0 && wname
!= NULL
) {
2454 // first, the whole rest
2455 res
= ufoFindWordInVocAndParents(wname
, wnlen
, 0, vocid
, 1);
2460 wname
= ufoFindColon(wname
, wnlen
);
2461 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2462 ufo_assert(xlen
> 0 && xlen
< 255);
2463 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2466 if (wname
!= NULL
) {
2467 // it should be a vocabulary
2468 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2469 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2470 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2486 //==========================================================================
2490 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2494 //==========================================================================
2495 static uint32_t ufoFindWord (const char *wname
) {
2497 if (wname
&& wname
[0] != 0) {
2498 const size_t wnlen
= strlen(wname
);
2499 ufo_assert(wnlen
< 8192);
2500 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2501 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2503 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2505 // first search in context
2506 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2508 // now try vocabulary stack
2509 uint32_t vstp
= ufoVSP
;
2510 while (res
== 0 && vstp
!= 0) {
2512 ctx
= ufoVocStack
[vstp
];
2513 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2516 // if not found, try name resolution
2517 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2524 //==========================================================================
2526 // ufoCreateWordHeader
2528 // create word header up to CFA, link to the current dictionary
2530 //==========================================================================
2531 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2532 if (wname
== NULL
) wname
= "";
2533 const size_t wnlen
= strlen(wname
);
2534 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2535 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2536 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2537 ufo_assert(curr
!= 0);
2539 const uint32_t warn
= ufoImgGetU32(ufoAddrRedefineWarning
);
2540 if (wnlen
!= 0 && warn
!= UFO_REDEF_WARN_DONT_CARE
) {
2542 if (warn
!= UFO_REDEF_WARN_PARENTS
) {
2543 cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2545 cfa
= ufoFindWordInVocAndParents(wname
, wnlen
, hash
, curr
, 1);
2548 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2549 const uint32_t flags
= ufoImgGetU32(nfa
);
2550 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2551 ufoFatal("trying to redefine protected word '%s'", wname
);
2552 } else if (warn
!= UFO_REDEF_WARN_NONE
) {
2553 ufoWarning("redefining word '%s'", wname
);
2557 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2558 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2559 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2561 const uint32_t xfaAddr
= UFO_GET_DP();
2562 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2563 // link previous yfa here
2564 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2565 // fix YFA of the previous word
2567 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2569 // our XFA points to the previous XFA
2570 ufoImgEmitU32(lastxfa
); // xfa
2572 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2574 ufoImgEmitU32(0); // xfa
2576 ufoImgEmitU32(0); // yfa
2577 // bucket link (bfa)
2578 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2581 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2582 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2583 wname
, curr
, htbl
, bkt
);
2584 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2586 // bfa points to bfa
2587 const uint32_t bfa
= UFO_GET_DP();
2588 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2589 ufoImgPutU32(htbl
+ bkt
, bfa
);
2592 const uint32_t lfa
= UFO_GET_DP();
2593 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2595 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2597 ufoImgEmitU32(hash
);
2599 const uint32_t nfa
= UFO_GET_DP();
2600 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2601 const uint32_t nstart
= UFO_GET_DP();
2603 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2604 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2606 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2607 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2608 // name length, again
2609 ufo_assert(nend
- nstart
<= 255);
2610 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2611 ufo_assert((UFO_GET_DP() & 3) == 0);
2612 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2613 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2614 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2615 fprintf(stderr
, "*** NEW HEADER ***\n");
2616 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2617 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2618 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2619 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2620 ufoDumpWordHeader(lfa
);
2623 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2628 //==========================================================================
2632 //==========================================================================
2633 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2636 while (addr
< eaddr
) {
2637 uint32_t cfa
= ufoImgGetU32(addr
);
2638 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2639 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2640 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2641 uint32_t flags
= ufoImgGetU32(nfa
);
2642 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2643 uint32_t nlen
= flags
& 0xffU
;
2644 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2645 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2646 if (ch
<= 32 || ch
>= 127) {
2647 fprintf(fo
, "\\x%02x", ch
);
2649 fprintf(fo
, "%c", (char)ch
);
2653 switch (flags
& UFW_WARG_MASK
) {
2656 case UFW_WARG_BRANCH
:
2657 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2660 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2661 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2663 case UFW_WARG_C4STRZ
:
2664 count
= ufoImgGetU32(addr
); addr
+= 4;
2666 fprintf(fo
, " str:");
2667 for (int f
= 0; f
< count
; f
+= 1) {
2668 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2669 if (ch
<= 32 || ch
>= 127) {
2670 fprintf(fo
, "\\x%02x", ch
);
2672 fprintf(fo
, "%c", (char)ch
);
2675 addr
+= 1u; // skip zero byte
2676 addr
= UFO_ALIGN4(addr
);
2679 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2680 fprintf(fo
, " CFA:%u: ", cfa
);
2681 nfa
= UFO_CFA_TO_NFA(cfa
);
2682 nlen
= ufoImgGetU8(nfa
);
2683 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2684 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2685 if (ch
<= 32 || ch
>= 127) {
2686 fprintf(fo
, "\\x%02x", ch
);
2688 fprintf(fo
, "%c", (char)ch
);
2692 case UFW_WARG_CBLOCK
:
2693 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2695 case UFW_WARG_VOCID
:
2696 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2698 case UFW_WARG_C1STRZ
:
2699 count
= ufoImgGetU8(addr
); addr
+= 1;
2701 case UFW_WARG_DATASKIP
:
2702 fprintf(fo
, " DATA:%u", ufoImgGetU32(addr
));
2703 addr
+= ufoImgGetU32(addr
) + 4u;
2706 fprintf(fo
, " -- WTF?!\n");
2714 //==========================================================================
2718 //==========================================================================
2719 static void ufoDecompileWord (const uint32_t cfa
) {
2721 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
2722 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
2723 ufoDumpWordHeader(lfa
);
2724 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
2725 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
2726 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
2727 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
2728 fprintf(stdout
, "=======================\n");
2734 //==========================================================================
2736 // ufoBTShowWordName
2738 //==========================================================================
2739 static void ufoBTShowWordName (uint32_t nfa
) {
2741 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
2742 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2744 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
2745 if (ch
<= 32 || ch
>= 127) {
2746 fprintf(stderr
, "\\x%02x", ch
);
2748 fprintf(stderr
, "%c", (char)ch
);
2755 //==========================================================================
2759 //==========================================================================
2760 static void ufoBacktrace (uint32_t ip
, int showDataStack
) {
2761 // dump data stack (top 16)
2763 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2765 if (showDataStack
) {
2766 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
2767 uint32_t xsp
= ufoSP
;
2768 if (xsp
> 16) xsp
= 16;
2769 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2770 fprintf(stderr
, " %2u: 0x%08x %d%s\n",
2771 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
2772 (sp
== 0 ? " -- TOS" : ""));
2774 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
2777 // dump return stack (top 32)
2782 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
2784 nfa
= ufoFindWordForIP(ip
);
2786 fprintf(stderr
, " **: %8u -- ", ip
);
2787 ufoBTShowWordName(nfa
);
2788 fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
2789 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2790 fputc('\n', stderr
);
2793 uint32_t rp
= ufoRP
;
2794 uint32_t rscount
= 0;
2795 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
2796 while (rscount
!= 32 && rp
!= 0) {
2798 const uint32_t val
= ufoRStack
[rp
];
2799 nfa
= ufoFindWordForIP(val
);
2801 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
2802 ufoBTShowWordName(nfa
);
2803 fname
= ufoFindFileForIP(val
- 4u, &fline
, NULL
, NULL
);
2804 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2805 fputc('\n', stderr
);
2807 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
2811 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
2817 //==========================================================================
2821 //==========================================================================
2823 static void ufoDumpVocab (uint32_t vocid) {
2825 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2826 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2827 vochdr = ufoImgGetU32(vochdr);
2829 fprintf(stderr, "--- HEADER ---\n");
2830 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2831 fprintf(stderr, "========\n");
2832 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2833 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2834 fprintf(stderr, "--- HASH TABLE ---\n");
2835 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2836 uint32_t bfa = ufoImgGetU32(htbl);
2838 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2840 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2841 bfa = ufoImgGetU32(bfa);
2853 // if set, this will be used when we are out of include files. intended for UrAsm.
2854 // return 0 if there is no more lines, otherwise the string should be copied
2855 // to buffer, `*fname` and `*fline` should be properly set.
2856 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
2859 //==========================================================================
2861 // ufoLoadNextUserLine
2863 //==========================================================================
2864 static int ufoLoadNextUserLine (void) {
2865 uint32_t tibPos
= 0;
2866 const char *fname
= NULL
;
2869 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
2870 ufoCurrFileLine
[510] = 0;
2871 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2872 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
2875 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2876 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2878 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2879 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2880 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2882 ufoTibPokeChOfs(0, tibPos
+ slen
);
2884 if (fname
== NULL
) fname
= "<user>";
2885 ufoSetInFileName(fname
);
2886 ufoInFileLine
= fline
;
2894 //==========================================================================
2896 // ufoLoadNextLine_NativeMode
2898 // load next file line into TIB
2899 // always strips final '\n'
2901 // return 0 on EOF, 1 on success
2903 //==========================================================================
2904 static int ufoLoadNextLine (int crossInclude
) {
2906 uint32_t tibPos
= 0;
2909 if (ufoMode
== UFO_MODE_MACRO
) {
2910 //fprintf(stderr, "***MAC!\n");
2914 while (ufoInFile
!= NULL
&& !done
) {
2915 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
2916 // check for a newline
2917 // if there is no newline char at the end, the string was truncated
2918 ufoCurrFileLine
[510] = 0;
2919 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2920 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2921 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2923 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2924 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2925 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2927 ufoTibPokeChOfs(0, tibPos
+ slen
);
2929 if (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
2933 // continuation, nothing to do
2936 // if we read nothing, this is EOF
2937 if (tibPos
== 0 && crossInclude
) {
2938 // we read nothing, and allowed to cross include boundaries
2947 // eof, try user-supplied input
2948 if (ufoFileStackPos
== 0) {
2949 return ufoLoadNextUserLine();
2954 // if we read at least something, this is not EOF
2960 // ////////////////////////////////////////////////////////////////////////// //
2965 UFWORD(DUMP_STACK
) {
2966 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2967 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
2968 uint32_t xsp
= ufoSP
;
2969 if (xsp
> 16) xsp
= 16;
2970 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2971 printf(" %2u: 0x%08x %d%s\n",
2972 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
2973 (sp
== 0 ? " -- TOS" : ""));
2975 if (ufoSP
> 16) printf(" ...more...\n");
2976 ufoLastEmitWasCR
= 1;
2981 UFWORD(UFO_BACKTRACE
) {
2983 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2984 if (ufoInFile
!= NULL
) {
2985 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
2987 fprintf(stderr
, "*** somewhere in time ***\n");
2989 ufoBacktrace(ufoIP
, 1);
2994 UFWORD(DUMP_STACK_TASK
) {
2995 UfoState
*st
= ufoFindState(ufoPop());
2996 if (st
== NULL
) ufoFatal("invalid state id");
2997 // temporarily switch the task
2998 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3000 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3001 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
3002 uint32_t xsp
= ufoSP
;
3003 if (xsp
> 16) xsp
= 16;
3004 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
3005 printf(" %2u: 0x%08x %d%s\n",
3006 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
3007 (sp
== 0 ? " -- TOS" : ""));
3009 if (ufoSP
> 16) printf(" ...more...\n");
3010 ufoLastEmitWasCR
= 1;
3012 ufoCurrState
= oldst
;
3017 UFWORD(DUMP_RSTACK_TASK
) {
3018 UfoState
*st
= ufoFindState(ufoPop());
3019 if (st
== NULL
) ufoFatal("invalid state id");
3020 // temporarily switch the task
3021 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3024 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3025 if (ufoInFile
!= NULL
) {
3026 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3028 fprintf(stderr
, "*** somewhere in time ***\n");
3030 ufoBacktrace(ufoIP
, 0);
3032 ufoCurrState
= oldst
;
3037 UFWORD(UFO_BACKTRACE_TASK
) {
3038 UfoState
*st
= ufoFindState(ufoPop());
3039 if (st
== NULL
) ufoFatal("invalid state id");
3040 // temporarily switch the task
3041 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3044 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3045 if (ufoInFile
!= NULL
) {
3046 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3048 fprintf(stderr
, "*** somewhere in time ***\n");
3050 ufoBacktrace(ufoIP
, 1);
3052 ufoCurrState
= oldst
;
3056 // ////////////////////////////////////////////////////////////////////////// //
3057 // some init words, and PAD
3062 UFWORD(SP0_STORE
) { ufoSP
= 0; }
3067 if (ufoRP
!= ufoRPTop
) {
3069 // we need to push a dummy value
3070 ufoRPush(0xdeadf00d);
3076 // PAD is at the beginning of temp area
3078 ufoPush(UFO_PAD_ADDR
);
3082 // ////////////////////////////////////////////////////////////////////////// //
3083 // peeks and pokes with address register
3094 UFWORD(REGA_STORE
) {
3102 const uint32_t newa
= ufoPop();
3115 UFWORD(REGA_INC_CELL
) {
3128 ufoRegA
= ufoRPop();
3132 // ////////////////////////////////////////////////////////////////////////// //
3133 // useful to work with handles and normal addreses uniformly
3138 UFWORD(CPEEK_REGA_IDX
) {
3139 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3140 const uint32_t idx
= ufoPop();
3141 const uint32_t newaddr
= ufoRegA
+ idx
;
3142 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3143 ufoPush(ufoImgGetU8Ext(newaddr
));
3145 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3146 ufoRegA
, idx
, newaddr
);
3150 UFCALL(PAR_HANDLE_LOAD_BYTE
);
3156 UFWORD(WPEEK_REGA_IDX
) {
3157 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3158 const uint32_t idx
= ufoPop();
3159 const uint32_t newaddr
= ufoRegA
+ idx
;
3160 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3161 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3163 ufoPush(ufoImgGetU16(newaddr
));
3165 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3166 ufoRegA
, idx
, newaddr
);
3170 UFCALL(PAR_HANDLE_LOAD_WORD
);
3176 UFWORD(PEEK_REGA_IDX
) {
3177 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3178 const uint32_t idx
= ufoPop();
3179 const uint32_t newaddr
= ufoRegA
+ idx
;
3180 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3181 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3183 ufoPush(ufoImgGetU32(newaddr
));
3185 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3186 ufoRegA
, idx
, newaddr
);
3190 UFCALL(PAR_HANDLE_LOAD_CELL
);
3196 UFWORD(CPOKE_REGA_IDX
) {
3197 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3198 const uint32_t idx
= ufoPop();
3199 const uint32_t newaddr
= ufoRegA
+ idx
;
3200 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3201 const uint32_t value
= ufoPop();
3202 ufoImgPutU8(newaddr
, value
);
3204 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3205 ufoRegA
, idx
, newaddr
);
3209 UFCALL(PAR_HANDLE_STORE_BYTE
);
3215 UFWORD(WPOKE_REGA_IDX
) {
3216 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3217 const uint32_t idx
= ufoPop();
3218 const uint32_t newaddr
= ufoRegA
+ idx
;
3219 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3220 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3222 const uint32_t value
= ufoPop();
3223 ufoImgPutU16(newaddr
, value
);
3225 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3226 ufoRegA
, idx
, newaddr
);
3230 UFCALL(PAR_HANDLE_STORE_WORD
);
3236 UFWORD(POKE_REGA_IDX
) {
3237 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3238 const uint32_t idx
= ufoPop();
3239 const uint32_t newaddr
= ufoRegA
+ idx
;
3240 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3241 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3243 const uint32_t value
= ufoPop();
3244 ufoImgPutU32(newaddr
, value
);
3246 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3247 ufoRegA
, idx
, newaddr
);
3251 UFCALL(PAR_HANDLE_STORE_CELL
);
3256 // ////////////////////////////////////////////////////////////////////////// //
3261 // ( addr -- value8 )
3263 ufoPush(ufoImgGetU8Ext(ufoPop()));
3267 // ( addr -- value16 )
3269 const uint32_t addr
= ufoPop();
3270 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3271 ufoPush(ufoImgGetU16(addr
));
3275 UFCALL(PAR_HANDLE_LOAD_WORD
);
3280 // ( addr -- value32 )
3282 const uint32_t addr
= ufoPop();
3283 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3284 ufoPush(ufoImgGetU32(addr
));
3288 UFCALL(PAR_HANDLE_LOAD_CELL
);
3295 const uint32_t addr
= ufoPop();
3296 const uint32_t val
= ufoPop();
3297 ufoImgPutU8Ext(addr
, val
);
3301 // ( val16 addr -- )
3303 const uint32_t addr
= ufoPop();
3304 const uint32_t val
= ufoPop();
3305 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3306 ufoImgPutU16(addr
, val
);
3311 UFCALL(PAR_HANDLE_STORE_WORD
);
3316 // ( val32 addr -- )
3318 const uint32_t addr
= ufoPop();
3319 const uint32_t val
= ufoPop();
3320 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3321 ufoImgPutU32(addr
, val
);
3326 UFCALL(PAR_HANDLE_STORE_CELL
);
3331 // ////////////////////////////////////////////////////////////////////////// //
3332 // dictionary emitters
3337 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
3341 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
3345 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
3348 // ////////////////////////////////////////////////////////////////////////// //
3354 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3358 // (LITCFA) ( -- n )
3359 UFWORD(PAR_LITCFA
) {
3360 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3364 // (LITVOCID) ( -- n )
3365 UFWORD(PAR_LITVOCID
) {
3366 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3371 UFWORD(PAR_LITSTR8
) {
3372 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
3375 ufoIP
+= count
+ 1; // 1 for terminating 0
3377 ufoIP
= UFO_ALIGN4(ufoIP
);
3381 // ////////////////////////////////////////////////////////////////////////// //
3386 UFWORD(PAR_BRANCH
) {
3387 ufoIP
= ufoImgGetU32(ufoIP
);
3390 // (TBRANCH) ( flag )
3391 UFWORD(PAR_TBRANCH
) {
3393 ufoIP
= ufoImgGetU32(ufoIP
);
3399 // (0BRANCH) ( flag )
3400 UFWORD(PAR_0BRANCH
) {
3402 ufoIP
= ufoImgGetU32(ufoIP
);
3408 // (+0BRANCH) ( flag )
3409 UFWORD(PAR_P0BRANCH
) {
3410 if ((ufoPop() & 0x80000000u
) == 0) {
3411 ufoIP
= ufoImgGetU32(ufoIP
);
3417 // (+BRANCH) ( flag )
3418 UFWORD(PAR_PBRANCH
) {
3419 const uint32_t v
= ufoPop();
3420 if (v
> 0 && v
< 0x80000000u
) {
3421 ufoIP
= ufoImgGetU32(ufoIP
);
3427 // (-0BRANCH) ( flag )
3428 UFWORD(PAR_M0BRANCH
) {
3429 const uint32_t v
= ufoPop();
3430 if (v
== 0 || v
>= 0x80000000u
) {
3431 ufoIP
= ufoImgGetU32(ufoIP
);
3437 // (-BRANCH) ( flag )
3438 UFWORD(PAR_MBRANCH
) {
3439 if ((ufoPop() & 0x80000000u
) != 0) {
3440 ufoIP
= ufoImgGetU32(ufoIP
);
3446 // (DATASKIP) ( -- )
3447 UFWORD(PAR_DATASKIP
) {
3448 ufoIP
+= ufoImgGetU32(ufoIP
) + 4u;
3452 // ////////////////////////////////////////////////////////////////////////// //
3453 // execute words by CFA
3462 // EXECUTE-TAIL ( cfa )
3463 UFWORD(EXECUTE_TAIL
) {
3470 // ////////////////////////////////////////////////////////////////////////// //
3471 // word termination, locals support
3481 UFWORD(PAR_LENTER
) {
3482 // low byte of loccount is total number of locals
3483 // high byte is the number of args
3484 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3485 uint32_t acount
= (lcount
>> 8) & 0xff;
3487 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3488 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3489 ufoFatal("out of locals stack");
3492 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3493 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3494 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3495 ufoLBP
= newbp
; ufoLP
+= lcount
;
3498 while (newbp
!= ufoLBP
) {
3499 ufoLStack
[newbp
] = ufoPop();
3505 UFWORD(PAR_LLEAVE
) {
3506 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3507 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3509 ufoLBP
= ufoLStack
[ufoLBP
];
3512 //==========================================================================
3516 //==========================================================================
3517 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
3518 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3519 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3520 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3523 //==========================================================================
3527 //==========================================================================
3528 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
3529 const uint32_t value
= ufoPop();
3530 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3531 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3532 ufoLStack
[ufoLBP
+ lidx
] = value
;
3537 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3541 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3544 // ////////////////////////////////////////////////////////////////////////// //
3545 // stack manipulation
3550 UFWORD(DUP
) { ufoDup(); }
3552 // ( n -- n n ) | ( 0 -- 0 )
3553 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3555 // ( n0 n1 -- n0 n1 n0 n1 )
3556 UFWORD(DDUP
) { ufo2Dup(); }
3559 UFWORD(DROP
) { ufoDrop(); }
3562 UFWORD(DDROP
) { ufo2Drop(); }
3564 // ( n0 n1 -- n1 n0 )
3565 UFWORD(SWAP
) { ufoSwap(); }
3567 // ( n0 n1 -- n1 n0 )
3568 UFWORD(DSWAP
) { ufo2Swap(); }
3570 // ( n0 n1 -- n0 n1 n0 )
3571 UFWORD(OVER
) { ufoOver(); }
3573 // ( n0 n1 -- n0 n1 n0 )
3574 UFWORD(DOVER
) { ufo2Over(); }
3576 // ( n0 n1 n2 -- n1 n2 n0 )
3577 UFWORD(ROT
) { ufoRot(); }
3579 // ( n0 n1 n2 -- n2 n0 n1 )
3580 UFWORD(NROT
) { ufoNRot(); }
3584 UFWORD(RDUP
) { ufoRDup(); }
3587 UFWORD(RDROP
) { ufoRDrop(); }
3591 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3594 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3597 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3602 const uint32_t n
= ufoPop();
3603 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3604 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3610 const uint32_t n
= ufoPop();
3611 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3612 const uint32_t rp
= ufoRP
- n
- 1u;
3613 ufoPush(ufoRStack
[rp
]);
3619 const uint32_t n
= ufoPop();
3620 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3622 case 0: break; // do nothing
3623 case 1: ufoSwap(); break;
3624 case 2: ufoRot(); break;
3627 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3628 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3629 ufoDStack
[ufoSP
- 1u] = val
;
3638 const uint32_t n
= ufoPop();
3639 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3641 const uint32_t rp
= ufoRP
- n
- 1u;
3642 const uint32_t val
= ufoRStack
[rp
];
3643 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3644 ufoRStack
[ufoRP
- 1u] = val
;
3649 // ( | a b -- | b a )
3651 const uint32_t b
= ufoRPop();
3652 const uint32_t a
= ufoRPop();
3653 ufoRPush(b
); ufoRPush(a
);
3657 // ( | a b -- | a b a )
3659 const uint32_t b
= ufoRPop();
3660 const uint32_t a
= ufoRPop();
3661 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3665 // ( | a b c -- | b c a )
3667 const uint32_t c
= ufoRPop();
3668 const uint32_t b
= ufoRPop();
3669 const uint32_t a
= ufoRPop();
3670 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3674 // ( | a b c -- | c a b )
3676 const uint32_t c
= ufoRPop();
3677 const uint32_t b
= ufoRPop();
3678 const uint32_t a
= ufoRPop();
3679 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3683 // ////////////////////////////////////////////////////////////////////////// //
3690 ufoPushBool(ufoLoadNextLine(1));
3695 UFWORD(REFILL_NOCROSS
) {
3696 ufoPushBool(ufoLoadNextLine(0));
3702 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3707 UFWORD(TIB_PEEKCH
) {
3708 ufoPush(ufoTibPeekCh());
3713 UFWORD(TIB_PEEKCH_OFS
) {
3714 const uint32_t ofs
= ufoPop();
3715 ufoPush(ufoTibPeekChOfs(ofs
));
3721 ufoPush(ufoTibGetCh());
3726 UFWORD(TIB_SKIPCH
) {
3731 // ////////////////////////////////////////////////////////////////////////// //
3735 //==========================================================================
3739 //==========================================================================
3740 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3741 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3745 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3746 // does base TIB parsing; never copies anything.
3747 // as our reader is line-based, returns FALSE on EOL.
3748 // EOL is detected after skipping leading delimiters.
3749 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3750 // trailing delimiter is always skipped.
3752 const uint32_t skipDelim
= ufoPop();
3753 const uint32_t delim
= ufoPop();
3756 if (delim
== 0 || delim
> 0xffU
) {
3758 while (ufoTibGetCh() != 0) {}
3761 ch
= ufoTibPeekCh();
3762 // skip initial delimiters
3764 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3766 ch
= ufoTibPeekCh();
3773 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3775 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3778 ch
= ufoTibPeekCh();
3781 if (ch
!= 0) ufoTibSkipCh();
3789 // PARSE-SKIP-BLANKS
3791 UFWORD(PARSE_SKIP_BLANKS
) {
3792 uint8_t ch
= ufoTibPeekCh();
3793 while (ch
!= 0 && ch
<= 32) {
3795 ch
= ufoTibPeekCh();
3799 //==========================================================================
3801 // ufoParseMLComment
3803 // initial two chars are skipped
3805 //==========================================================================
3806 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3809 while (level
!= 0) {
3813 UFCALL(REFILL_NOCROSS
);
3814 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3816 ufoFatal("unexpected end of line in comment");
3819 ch1
= ufoTibPeekCh();
3820 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3821 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3822 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3827 // (PARSE-SKIP-COMMENTS)
3828 // ( allow-multiline? -- )
3829 // skip all blanks and comments
3830 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3831 const uint32_t allowMulti
= ufoPop();
3833 ch
= ufoTibPeekCh();
3835 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3840 ch
= ufoTibPeekCh();
3842 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3844 } else if (ch
== '(') {
3846 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3847 ufoTibPeekChOfs(0));
3849 ch1
= ufoTibPeekChOfs(1);
3851 // single-line comment
3852 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3853 ch
= ufoTibPeekCh();
3854 } else if ((ch1
== '*' || ch1
== '(') && ufoTibPeekChOfs(2) <= 32) {
3855 // possibly multiline
3856 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3857 ufoParseMLComment(allowMulti
, (ch1
== '('));
3858 ch
= ufoTibPeekCh();
3862 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3863 // single-line comment
3864 while (ch
!= 0) ch
= ufoTibGetCh();
3865 } else if ((ch
== ';' || ch
== '-' || ch
== '/') && (ufoTibPeekChOfs(1) == ch
)) {
3867 while (ch
!= 0) ch
= ufoTibGetCh();
3873 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3879 UFWORD(PARSE_SKIP_LINE
) {
3880 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3881 if (ufoPop() != 0) {
3887 // ( -- addr count )
3888 // parse with leading blanks skipping. doesn't copy anything.
3889 // return empty string on EOL.
3890 UFWORD(PARSE_NAME
) {
3891 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3892 if (ufoPop() == 0) {
3899 // ( delim -- addr count TRUE / FALSE )
3900 // parse without skipping delimiters; never copies anything.
3901 // as our reader is line-based, returns FALSE on EOL.
3902 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3903 // trailing delimiter is always skipped.
3905 ufoPushBool(0); UFCALL(PAR_PARSE
);
3909 // ////////////////////////////////////////////////////////////////////////// //
3915 UFWORD(PAR_NORM_EMIT_CHAR
) {
3916 uint32_t ch
= ufoPop()&0xffU
;
3917 if (ch
< 32 || ch
== 127) {
3918 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
3923 // (NORM-XEMIT-CHAR)
3925 UFWORD(PAR_NORM_XEMIT_CHAR
) {
3926 uint32_t ch
= ufoPop()&0xffU
;
3927 if (ch
< 32 || ch
== 127) ch
= '?';
3934 uint32_t ch
= ufoPop()&0xffU
;
3935 ufoLastEmitWasCR
= (ch
== 10);
3942 ufoPushBool(ufoLastEmitWasCR
);
3948 ufoLastEmitWasCR
= !!ufoPop();
3953 UFWORD(FLUSH_EMIT
) {
3958 // ////////////////////////////////////////////////////////////////////////// //
3962 #define UF_UMATH(name_,op_) \
3964 const uint32_t a = ufoPop(); \
3968 #define UF_BMATH(name_,op_) \
3970 const uint32_t b = ufoPop(); \
3971 const uint32_t a = ufoPop(); \
3975 #define UF_BDIV(name_,op_) \
3977 const uint32_t b = ufoPop(); \
3978 const uint32_t a = ufoPop(); \
3979 if (b == 0) ufoFatal("division by zero"); \
3983 #define UFO_POP_U64() ({ \
3984 const uint32_t hi_ = ufoPop(); \
3985 const uint32_t lo_ = ufoPop(); \
3986 (((uint64_t)hi_ << 32) | lo_); \
3989 // this is UB by the idiotic C standard. i don't care.
3990 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
3992 #define UFO_PUSH_U64(vn_) do { \
3993 ufoPush((uint32_t)(vn_)); \
3994 ufoPush((uint32_t)((vn_) >> 32)); \
3997 // this is UB by the idiotic C standard. i don't care.
3998 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
4002 UF_BMATH(PLUS
, a
+ b
);
4006 UF_BMATH(MINUS
, a
- b
);
4010 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
4014 UF_BMATH(UMUL
, a
* b
);
4018 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
4022 UF_BDIV(UDIV
, a
/ b
);
4026 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
4030 UF_BDIV(UMOD
, a
% b
);
4033 // ( a b -- a/b, a%b )
4035 const int32_t b
= (int32_t)ufoPop();
4036 const int32_t a
= (int32_t)ufoPop();
4037 if (b
== 0) ufoFatal("division by zero");
4038 ufoPush((uint32_t)(a
/b
));
4039 ufoPush((uint32_t)(a
%b
));
4043 // ( a b -- a/b, a%b )
4045 const uint32_t b
= ufoPop();
4046 const uint32_t a
= ufoPop();
4047 if (b
== 0) ufoFatal("division by zero");
4048 ufoPush((uint32_t)(a
/b
));
4049 ufoPush((uint32_t)(a
%b
));
4053 // ( a b c -- a*b/c )
4054 // this uses 64-bit intermediate value
4056 const int32_t c
= (int32_t)ufoPop();
4057 const int32_t b
= (int32_t)ufoPop();
4058 const int32_t a
= (int32_t)ufoPop();
4059 if (c
== 0) ufoFatal("division by zero");
4060 int64_t xval
= a
; xval
*= b
; xval
/= c
;
4061 ufoPush((uint32_t)(int32_t)xval
);
4065 // ( a b c -- a*b/c )
4066 // this uses 64-bit intermediate value
4068 const uint32_t c
= ufoPop();
4069 const uint32_t b
= ufoPop();
4070 const uint32_t a
= ufoPop();
4071 if (c
== 0) ufoFatal("division by zero");
4072 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
4073 ufoPush((uint32_t)xval
);
4077 // ( a b c -- a*b/c a*b%c )
4078 // this uses 64-bit intermediate value
4080 const int32_t c
= (int32_t)ufoPop();
4081 const int32_t b
= (int32_t)ufoPop();
4082 const int32_t a
= (int32_t)ufoPop();
4083 if (c
== 0) ufoFatal("division by zero");
4084 int64_t xval
= a
; xval
*= b
;
4085 ufoPush((uint32_t)(int32_t)(xval
/ c
));
4086 ufoPush((uint32_t)(int32_t)(xval
% c
));
4090 // ( a b c -- a*b/c )
4091 // this uses 64-bit intermediate value
4092 UFWORD(UMULDIVMOD
) {
4093 const uint32_t c
= ufoPop();
4094 const uint32_t b
= ufoPop();
4095 const uint32_t a
= ufoPop();
4096 if (c
== 0) ufoFatal("division by zero");
4097 uint64_t xval
= a
; xval
*= b
;
4098 ufoPush((uint32_t)(xval
/ c
));
4099 ufoPush((uint32_t)(xval
% c
));
4103 // ( a b -- lo(a*b) hi(a*b) )
4104 // this leaves 64-bit result
4106 const int32_t b
= (int32_t)ufoPop();
4107 const int32_t a
= (int32_t)ufoPop();
4108 int64_t xval
= a
; xval
*= b
;
4113 // ( a b -- lo(a*b) hi(a*b) )
4114 // this leaves 64-bit result
4116 const uint32_t b
= ufoPop();
4117 const uint32_t a
= ufoPop();
4118 uint64_t xval
= a
; xval
*= b
;
4123 // ( alo ahi b -- a/b a%b )
4125 const int32_t b
= (int32_t)ufoPop();
4126 if (b
== 0) ufoFatal("division by zero");
4127 int64_t a
= UFO_POP_I64();
4128 int32_t adiv
= (int32_t)(a
/ b
);
4129 int32_t amod
= (int32_t)(a
% b
);
4130 ufoPush((uint32_t)adiv
);
4131 ufoPush((uint32_t)amod
);
4135 // ( alo ahi b -- a/b a%b )
4137 const uint32_t b
= ufoPop();
4138 if (b
== 0) ufoFatal("division by zero");
4139 uint64_t a
= UFO_POP_U64();
4140 uint32_t adiv
= (uint32_t)(a
/ b
);
4141 uint32_t amod
= (uint32_t)(a
% b
);
4147 // ( alo ahi u -- lo hi )
4149 const uint32_t b
= ufoPop();
4150 uint64_t a
= UFO_POP_U64();
4156 // ( lo0 hi0 lo1 hi1 -- lo hi )
4158 uint64_t n1
= UFO_POP_U64();
4159 uint64_t n0
= UFO_POP_U64();
4165 // ( lo0 hi0 lo1 hi1 -- lo hi )
4167 uint64_t n1
= UFO_POP_U64();
4168 uint64_t n0
= UFO_POP_U64();
4174 // ( lo0 hi0 lo1 hi1 -- bool )
4176 uint64_t n1
= UFO_POP_U64();
4177 uint64_t n0
= UFO_POP_U64();
4178 ufoPushBool(n0
== n1
);
4182 // ( lo0 hi0 lo1 hi1 -- bool )
4184 int64_t n1
= UFO_POP_I64();
4185 int64_t n0
= UFO_POP_I64();
4186 ufoPushBool(n0
< n1
);
4190 // ( lo0 hi0 lo1 hi1 -- bool )
4192 int64_t n1
= UFO_POP_I64();
4193 int64_t n0
= UFO_POP_I64();
4194 ufoPushBool(n0
<= n1
);
4198 // ( lo0 hi0 lo1 hi1 -- bool )
4200 uint64_t n1
= UFO_POP_U64();
4201 uint64_t n0
= UFO_POP_U64();
4202 ufoPushBool(n0
< n1
);
4206 // ( lo0 hi0 lo1 hi1 -- bool )
4208 uint64_t n1
= UFO_POP_U64();
4209 uint64_t n0
= UFO_POP_U64();
4210 ufoPushBool(n0
<= n1
);
4214 // ( dlo dhi n -- nmod ndiv )
4215 // rounds toward zero
4217 const int32_t n
= (int32_t)ufoPop();
4218 if (n
== 0) ufoFatal("division by zero");
4219 int64_t d
= UFO_POP_I64();
4220 int32_t ndiv
= (int32_t)(d
/ n
);
4221 int32_t nmod
= (int32_t)(d
% n
);
4227 // ( dlo dhi n -- nmod ndiv )
4228 // rounds toward negative infinity
4230 const int32_t n
= (int32_t)ufoPop();
4231 if (n
== 0) ufoFatal("division by zero");
4232 int64_t d
= UFO_POP_I64();
4233 int32_t ndiv
= (int32_t)(d
/ n
);
4234 int32_t nmod
= (int32_t)(d
% n
);
4235 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
4244 // ////////////////////////////////////////////////////////////////////////// //
4245 // simple logic and bit manipulation
4248 #define UF_CMP(name_,op_) \
4250 const uint32_t b = ufoPop(); \
4251 const uint32_t a = ufoPop(); \
4257 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
4261 UF_CMP(ULESS
, a
< b
);
4265 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
4269 UF_CMP(UGREAT
, a
> b
);
4273 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
4277 UF_CMP(ULESSEQU
, a
<= b
);
4281 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
4285 UF_CMP(UGREATEQU
, a
>= b
);
4289 UF_CMP(EQU
, a
== b
);
4293 UF_CMP(NOTEQU
, a
!= b
);
4298 const uint32_t a
= ufoPop();
4299 ufoPushBool(a
== 0);
4304 UFWORD(ZERO_NOTEQU
) {
4305 const uint32_t a
= ufoPop();
4306 ufoPushBool(a
!= 0);
4311 UF_CMP(LOGAND
, a
&& b
);
4315 UF_CMP(LOGOR
, a
|| b
);
4320 const uint32_t b
= ufoPop();
4321 const uint32_t a
= ufoPop();
4328 const uint32_t b
= ufoPop();
4329 const uint32_t a
= ufoPop();
4336 const uint32_t b
= ufoPop();
4337 const uint32_t a
= ufoPop();
4344 const uint32_t a
= ufoPop();
4350 // arithmetic shift; positive `n` shifts to the left
4352 int32_t c
= (int32_t)ufoPop();
4355 int32_t n
= (int32_t)ufoPop();
4357 if (n
< 0) n
= -1; else n
= 0;
4359 n
>>= (uint8_t)(-c
);
4361 ufoPush((uint32_t)n
);
4364 uint32_t u
= ufoPop();
4376 // logical shift; positive `n` shifts to the left
4378 int32_t c
= (int32_t) ufoPop();
4379 uint32_t u
= ufoPop();
4385 u
>>= (uint8_t)(-c
);
4399 // ////////////////////////////////////////////////////////////////////////// //
4400 // string unescaping
4404 // ( addr count -- addr count )
4405 UFWORD(PAR_UNESCAPE
) {
4406 const uint32_t count
= ufoPop();
4407 const uint32_t addr
= ufoPeek();
4408 if ((count
& ((uint32_t)1<<31)) == 0) {
4409 const uint32_t eaddr
= addr
+ count
;
4410 uint32_t caddr
= addr
;
4411 uint32_t daddr
= addr
;
4412 while (caddr
!= eaddr
) {
4413 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4414 if (ch
== '\\' && caddr
!= eaddr
) {
4415 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4417 case 'r': ch
= '\r'; break;
4418 case 'n': ch
= '\n'; break;
4419 case 't': ch
= '\t'; break;
4420 case 'e': ch
= '\x1b'; break;
4421 case '`': ch
= '"'; break; // special escape to insert double-quote
4422 case '"': ch
= '"'; break;
4423 case '\\': ch
= '\\'; break;
4425 if (eaddr
- daddr
>= 1) {
4426 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
4427 if (dg0
< 0) ufoFatal("invalid hex string escape");
4428 if (eaddr
- daddr
>= 2) {
4429 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
4430 if (dg1
< 0) ufoFatal("invalid hex string escape");
4431 ch
= (uint8_t)(dg0
* 16 + dg1
);
4438 ufoFatal("invalid hex string escape");
4441 default: ufoFatal("invalid string escape");
4444 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
4446 ufoPush(daddr
- addr
);
4453 // ////////////////////////////////////////////////////////////////////////// //
4454 // numeric conversions
4457 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4458 UFWORD(PAR_BASED_NUMBER
) {
4459 const uint32_t xbase
= ufoPop();
4460 const uint32_t allowSign
= ufoPop();
4461 int32_t count
= (int32_t)ufoPop();
4462 uint32_t addr
= ufoPop();
4468 if (allowSign
&& count
> 1) {
4469 ch
= ufoImgGetU8Ext(addr
);
4470 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
4471 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
4474 // special-based numbers
4475 if (count
>= 3 && ufoImgGetU8Ext(addr
) == '0') {
4476 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4477 case 'x': case 'X': base
= 16; break;
4478 case 'o': case 'O': base
= 8; break;
4479 case 'b': case 'B': base
= 2; break;
4480 case 'd': case 'D': base
= 10; break;
4483 if (base
) { addr
+= 2; count
-= 2; }
4484 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '$') {
4486 addr
+= 1; count
-= 1;
4487 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '#') {
4489 addr
+= 1; count
-= 1;
4490 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '%') {
4492 addr
+= 1; count
-= 1;
4493 } else if (count
>= 3 && ufoImgGetU8Ext(addr
) == '&') {
4494 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4495 case 'h': case 'H': base
= 16; break;
4496 case 'o': case 'O': base
= 8; break;
4497 case 'b': case 'B': base
= 2; break;
4498 case 'd': case 'D': base
= 10; break;
4501 if (base
) { addr
+= 2; count
-= 2; }
4502 } else if (xbase
< 12 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'B') {
4505 } else if (xbase
< 18 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'H') {
4508 } else if (xbase
< 25 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'O') {
4514 if (!base
&& xbase
< 255) base
= xbase
;
4516 if (count
<= 0 || base
< 1 || base
> 36) {
4520 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
4521 while (!error
&& count
!= 0) {
4522 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
4524 error
= 1; wasUnder
= 0; wasDig
= 1;
4525 dig
= digitInBase((char)ch
, (int)base
);
4527 nc
= n
* (uint32_t)base
;
4529 nc
+= (uint32_t)dig
;
4542 if (!error
&& wasDig
&& !wasUnder
) {
4543 if (allowSign
&& neg
) n
= ~n
+ 1u;
4553 // ////////////////////////////////////////////////////////////////////////// //
4554 // compiler-related, dictionary-related
4557 static char ufoWNameBuf
[256];
4559 // (CREATE-WORD-HEADER)
4560 // ( addr count word-flags -- )
4561 UFWORD(PAR_CREATE_WORD_HEADER
) {
4562 const uint32_t flags
= ufoPop();
4563 const uint32_t wlen
= ufoPop();
4564 const uint32_t waddr
= ufoPop();
4565 if (wlen
== 0) ufoFatal("word name expected");
4566 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4567 // copy to separate buffer
4568 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4569 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4571 ufoWNameBuf
[wlen
] = 0;
4572 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4575 // (CREATE-NAMELESS-WORD-HEADER)
4576 // ( word-flags -- )
4577 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4578 const uint32_t flags
= ufoPop();
4579 ufoCreateWordHeader("", flags
);
4583 // ( addr count -- cfa TRUE / FALSE)
4585 const uint32_t wlen
= ufoPop();
4586 const uint32_t waddr
= ufoPop();
4587 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4588 // copy to separate buffer
4589 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4590 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4592 ufoWNameBuf
[wlen
] = 0;
4593 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4605 // (FIND-WORD-IN-VOC)
4606 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4607 // find only in the given voc; no name resolution
4608 UFWORD(FIND_WORD_IN_VOC
) {
4609 const uint32_t allowHidden
= ufoPop();
4610 const uint32_t vocid
= ufoPop();
4611 const uint32_t wlen
= ufoPop();
4612 const uint32_t waddr
= ufoPop();
4613 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4614 // copy to separate buffer
4615 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4616 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4618 ufoWNameBuf
[wlen
] = 0;
4619 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4631 // (FIND-WORD-IN-VOC-AND-PARENTS)
4632 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4633 // find only in the given voc; no name resolution
4634 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4635 const uint32_t allowHidden
= ufoPop();
4636 const uint32_t vocid
= ufoPop();
4637 const uint32_t wlen
= ufoPop();
4638 const uint32_t waddr
= ufoPop();
4639 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4640 // copy to separate buffer
4641 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4642 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4644 ufoWNameBuf
[wlen
] = 0;
4645 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4658 // ////////////////////////////////////////////////////////////////////////// //
4659 // more compiler words
4662 // ////////////////////////////////////////////////////////////////////////// //
4663 // vocabulary and wordlist utilities
4668 UFWORD(PAR_GET_VSP
) {
4674 UFWORD(PAR_SET_VSP
) {
4675 const uint32_t vsp
= ufoPop();
4676 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4682 UFWORD(PAR_VSP_LOAD
) {
4683 const uint32_t vsp
= ufoPop();
4684 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4685 ufoPush(ufoVocStack
[vsp
]);
4690 UFWORD(PAR_VSP_STORE
) {
4691 const uint32_t vsp
= ufoPop();
4692 const uint32_t value
= ufoPop();
4693 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4694 ufoVocStack
[vsp
] = value
;
4698 // ////////////////////////////////////////////////////////////////////////// //
4699 // word field address conversion
4705 const uint32_t cfa
= ufoPop();
4706 ufoPush(UFO_CFA_TO_PFA(cfa
));
4712 const uint32_t cfa
= ufoPop();
4713 ufoPush(UFO_CFA_TO_NFA(cfa
));
4719 const uint32_t cfa
= ufoPop();
4720 ufoPush(UFO_CFA_TO_LFA(cfa
));
4724 // ( cfa -- wend-addr )
4726 const uint32_t cfa
= ufoPop();
4727 ufoPush(ufoGetWordEndAddr(cfa
));
4733 const uint32_t pfa
= ufoPop();
4734 ufoPush(UFO_PFA_TO_CFA(pfa
));
4740 const uint32_t pfa
= ufoPop();
4741 const uint32_t cfa
= UFO_PFA_TO_CFA(pfa
);
4742 ufoPush(UFO_CFA_TO_NFA(cfa
));
4748 const uint32_t nfa
= ufoPop();
4749 ufoPush(UFO_NFA_TO_CFA(nfa
));
4755 const uint32_t nfa
= ufoPop();
4756 const uint32_t cfa
= UFO_NFA_TO_CFA(nfa
);
4757 ufoPush(UFO_CFA_TO_PFA(cfa
));
4763 const uint32_t nfa
= ufoPop();
4764 ufoPush(UFO_NFA_TO_LFA(nfa
));
4770 const uint32_t lfa
= ufoPop();
4771 ufoPush(UFO_LFA_TO_CFA(lfa
));
4777 const uint32_t lfa
= ufoPop();
4778 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4779 ufoPush(UFO_CFA_TO_PFA(cfa
));
4785 const uint32_t lfa
= ufoPop();
4786 ufoPush(UFO_LFA_TO_BFA(lfa
));
4792 const uint32_t lfa
= ufoPop();
4793 ufoPush(UFO_LFA_TO_XFA(lfa
));
4799 const uint32_t lfa
= ufoPop();
4800 ufoPush(UFO_LFA_TO_YFA(lfa
));
4806 const uint32_t lfa
= ufoPop();
4807 ufoPush(UFO_LFA_TO_NFA(lfa
));
4811 // ( ip -- nfa / 0 )
4813 const uint32_t ip
= ufoPop();
4814 ufoPush(ufoFindWordForIP(ip
));
4818 // ( ip -- addr count line TRUE / FALSE )
4819 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4820 UFWORD(IP2FILELINE
) {
4821 const uint32_t ip
= ufoPop();
4823 const char *fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
4824 if (fname
!= NULL
) {
4826 uint32_t addr
= ufoPeek();
4828 while (*fname
!= 0) {
4829 ufoImgPutU8(addr
, *(const unsigned char *)fname
);
4830 fname
+= 1u; addr
+= 1u; count
+= 1u;
4832 ufoImgPutU8(addr
, 0); // just in case
4842 // IP->FILE-HASH/LINE
4843 // ( ip -- len hash line TRUE / FALSE )
4844 UFWORD(IP2FILEHASHLINE
) {
4845 const uint32_t ip
= ufoPop();
4846 uint32_t fline
, fhash
, flen
;
4847 const char *fname
= ufoFindFileForIP(ip
, &fline
, &flen
, &fhash
);
4848 if (fname
!= NULL
) {
4859 // ////////////////////////////////////////////////////////////////////////// //
4860 // string operations
4863 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4864 uint32_t hash
= 0x29a;
4865 if ((size
& ((uint32_t)1<<31)) == 0) {
4867 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4870 addr
+= 1u; size
-= 1u;
4880 //==========================================================================
4884 //==========================================================================
4885 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
4887 if ((count
& ((uint32_t)1<<31)) == 0) {
4889 while (res
!= 0 && count
!= 0) {
4890 res
= (toUpperU8(ufoImgGetU8Ext(addr0
)) == toUpperU8(ufoImgGetU8Ext(addr1
)));
4891 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
4900 // ( a0 c0 a1 c1 -- bool )
4902 int32_t c1
= (int32_t)ufoPop();
4903 uint32_t a1
= ufoPop();
4904 int32_t c0
= (int32_t)ufoPop();
4905 uint32_t a0
= ufoPop();
4910 while (res
!= 0 && c0
!= 0) {
4911 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4912 a0
+= 1; a1
+= 1; c0
-= 1;
4921 // ( a0 c0 a1 c1 -- bool )
4923 int32_t c1
= (int32_t)ufoPop();
4924 uint32_t a1
= ufoPop();
4925 int32_t c0
= (int32_t)ufoPop();
4926 uint32_t a0
= ufoPop();
4931 while (res
!= 0 && c0
!= 0) {
4932 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4933 a0
+= 1; a1
+= 1; c0
-= 1;
4941 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4942 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4943 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4944 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4946 const uint32_t pcount
= ufoPop();
4947 const uint32_t paddr
= ufoPop();
4948 const uint32_t tcount
= ufoPop();
4949 const uint32_t taddr
= ufoPop();
4950 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
4951 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
4952 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
4954 ufoPush(tcount
- f
);
4966 // ( addr count -- hash )
4968 uint32_t count
= ufoPop();
4969 uint32_t addr
= ufoPop();
4970 ufoPush(ufoHashBuf(addr
, count
, 0));
4974 // ( addr count -- hash )
4976 uint32_t count
= ufoPop();
4977 uint32_t addr
= ufoPop();
4978 ufoPush(ufoHashBuf(addr
, count
, 0x20));
4982 // ////////////////////////////////////////////////////////////////////////// //
4983 // conditional defines
4986 typedef struct UForthCondDefine_t UForthCondDefine
;
4987 struct UForthCondDefine_t
{
4991 UForthCondDefine
*next
;
4994 static UForthCondDefine
*ufoCondDefines
= NULL
;
4995 static char ufoErrMsgBuf
[4096];
4998 //==========================================================================
5002 //==========================================================================
5003 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
5004 const unsigned char *s0
= (const unsigned char *)str0
;
5005 const unsigned char *s1
= (const unsigned char *)str1
;
5006 while (*s0
&& *s1
) {
5007 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
5010 return (*s0
== 0 && *s1
== 0);
5014 //==========================================================================
5018 //==========================================================================
5019 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
5021 if ((count
& ((uint32_t)1<<31)) == 0) {
5022 const unsigned char *src
= (const unsigned char *)buf
;
5024 while (res
!= 0 && count
!= 0) {
5025 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
5026 src
+= 1; addr
+= 1u; count
-= 1u;
5035 //==========================================================================
5037 // ufoClearCondDefines
5039 //==========================================================================
5040 static void ufoClearCondDefines (void) {
5041 while (ufoCondDefines
) {
5042 UForthCondDefine
*df
= ufoCondDefines
;
5043 ufoCondDefines
= df
->next
;
5044 if (df
->name
) free(df
->name
);
5050 //==========================================================================
5054 //==========================================================================
5055 int ufoHasCondDefine (const char *name
) {
5057 if (name
!= NULL
&& name
[0] != 0) {
5058 const size_t nlen
= strlen(name
);
5060 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5061 UForthCondDefine
*dd
= ufoCondDefines
;
5062 while (res
== 0 && dd
!= NULL
) {
5063 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5064 res
= ufoStrEquCI(name
, dd
->name
);
5074 //==========================================================================
5078 //==========================================================================
5079 void ufoCondDefine (const char *name
) {
5080 if (name
!= NULL
&& name
[0] != 0) {
5081 const size_t nlen
= strlen(name
);
5082 if (nlen
> 255) ufoFatal("conditional define name too long");
5083 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5084 UForthCondDefine
*dd
= ufoCondDefines
;
5086 while (res
== 0 && dd
!= NULL
) {
5087 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5088 res
= ufoStrEquCI(name
, dd
->name
);
5094 dd
= calloc(1, sizeof(UForthCondDefine
));
5095 if (dd
== NULL
) ufoFatal("out of memory for defines");
5096 dd
->name
= strdup(name
);
5097 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5098 dd
->namelen
= (uint32_t)nlen
;
5100 dd
->next
= ufoCondDefines
;
5101 ufoCondDefines
= dd
;
5107 //==========================================================================
5111 //==========================================================================
5112 void ufoCondUndef (const char *name
) {
5113 if (name
!= NULL
&& name
[0] != 0) {
5114 const size_t nlen
= strlen(name
);
5116 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5117 UForthCondDefine
*dd
= ufoCondDefines
;
5118 UForthCondDefine
*prev
= NULL
;
5119 while (dd
!= NULL
) {
5120 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5121 if (ufoStrEquCI(name
, dd
->name
)) {
5122 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
5128 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
5136 // ( addr count -- )
5137 UFWORD(PAR_DLR_DEFINE
) {
5138 uint32_t count
= ufoPop();
5139 uint32_t addr
= ufoPop();
5140 if (count
== 0) ufoFatal("empty define");
5141 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5142 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5143 UForthCondDefine
*dd
;
5144 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5145 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5146 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
5150 dd
= calloc(1, sizeof(UForthCondDefine
));
5151 if (dd
== NULL
) ufoFatal("out of memory for defines");
5152 dd
->name
= calloc(1, count
+ 1u);
5153 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5154 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5155 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5157 dd
->namelen
= count
;
5159 dd
->next
= ufoCondDefines
;
5160 ufoCondDefines
= dd
;
5164 // ( addr count -- )
5165 UFWORD(PAR_DLR_UNDEF
) {
5166 uint32_t count
= ufoPop();
5167 uint32_t addr
= ufoPop();
5168 if (count
== 0) ufoFatal("empty define");
5169 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5170 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5171 UForthCondDefine
*prev
= NULL
;
5172 UForthCondDefine
*dd
;
5173 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
5174 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5175 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
5176 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
5186 // ( addr count -- bool )
5187 UFWORD(PAR_DLR_DEFINEDQ
) {
5188 uint32_t count
= ufoPop();
5189 uint32_t addr
= ufoPop();
5190 if (count
== 0) ufoFatal("empty define");
5191 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5192 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5194 UForthCondDefine
*dd
= ufoCondDefines
;
5195 while (!found
&& dd
!= NULL
) {
5196 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5197 found
= ufoBufEquCI(addr
, count
, dd
->name
);
5205 // ////////////////////////////////////////////////////////////////////////// //
5210 // ( addr count -- )
5212 uint32_t count
= ufoPop();
5213 uint32_t addr
= ufoPop();
5214 if (count
& (1u<<31)) ufoFatal("invalid error message");
5215 if (count
== 0) ufoFatal("some error");
5216 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
5217 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5218 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
5220 ufoErrMsgBuf
[count
] = 0;
5221 ufoFatal("%s", ufoErrMsgBuf
);
5224 // ////////////////////////////////////////////////////////////////////////// //
5228 static char ufoFNameBuf
[4096];
5231 //==========================================================================
5233 // ufoScanIncludeFileName
5235 // `*psys` and `*psoft` must be initialised!
5237 //==========================================================================
5238 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
5239 uint32_t *psys
, uint32_t *psoft
)
5243 ufo_assert(dest
!= NULL
);
5244 ufo_assert(destsz
> 0);
5246 while (count
!= 0) {
5247 ch
= ufoImgGetU8Ext(addr
);
5249 //if (system) ufoFatal("invalid file name (duplicate system mark)");
5251 } else if (ch
== '?') {
5252 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
5258 addr
+= 1; count
-= 1;
5259 ch
= ufoImgGetU8Ext(addr
);
5260 } while (ch
<= 32 && count
!= 0);
5263 if (count
== 0) ufoFatal("empty include file name");
5264 if (count
>= destsz
) ufoFatal("include file name too long");
5267 while (count
!= 0) {
5268 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
5269 addr
+= 1; count
-= 1;
5277 // return number of items in include stack
5278 UFWORD(PAR_INCLUDE_DEPTH
) {
5279 ufoPush(ufoFileStackPos
);
5282 // (INCLUDE-FILE-ID)
5283 // ( isp -- id ) -- isp 0 is current, then 1, etc.
5284 // each include file has unique non-zero id.
5285 UFWORD(PAR_INCLUDE_FILE_ID
) {
5286 const uint32_t isp
= ufoPop();
5289 } else if (isp
<= ufoFileStackPos
) {
5290 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5293 ufoFatal("invalid include stack index");
5297 // (INCLUDE-FILE-LINE)
5299 UFWORD(PAR_INCLUDE_FILE_LINE
) {
5300 const uint32_t isp
= ufoPop();
5302 ufoPush(ufoInFileLine
);
5303 } else if (isp
<= ufoFileStackPos
) {
5304 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5305 ufoPush(stk
->fline
);
5307 ufoFatal("invalid include stack index");
5311 // (INCLUDE-FILE-NAME)
5312 // ( isp -- addr count )
5313 // current file name; at PAD
5314 UFWORD(PAR_INCLUDE_FILE_NAME
) {
5315 const uint32_t isp
= ufoPop();
5316 const char *fname
= NULL
;
5318 fname
= ufoInFileName
;
5319 } else if (isp
<= ufoFileStackPos
) {
5320 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5323 ufoFatal("invalid include stack index");
5326 uint32_t addr
= ufoPop();
5328 while (fname
[count
] != 0) {
5329 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
5332 ufoImgPutU8Ext(addr
+ count
, 0);
5338 // ( addr count soft? system? -- )
5339 UFWORD(PAR_INCLUDE
) {
5340 uint32_t system
= ufoPop();
5341 uint32_t softinclude
= ufoPop();
5342 uint32_t count
= ufoPop();
5343 uint32_t addr
= ufoPop();
5345 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
5347 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5349 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
5350 &system
, &softinclude
);
5352 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5354 FILE *fl
= fopen(ffn
, "rb");
5356 FILE *fl
= fopen(ffn
, "r");
5359 if (softinclude
) { free(ffn
); return; }
5360 ufoFatal("include file '%s' not found", ffn
);
5362 #ifdef UFO_DEBUG_INCLUDE
5363 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
5368 ufoSetInFileNameReuse(ffn
);
5369 ufoFileId
= ufoLastUsedFileId
;
5370 setLastIncPath(ufoInFileName
, system
);
5371 // trigger next line loading
5373 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
5377 UFWORD(DLR_INCLUDE_IMM
) {
5378 int soft
= 0, system
= 0;
5379 // parse include filename
5380 //UFCALL(PARSE_SKIP_BLANKS);
5381 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5382 uint8_t ch
= ufoTibPeekCh();
5384 ufoTibSkipCh(); // skip quote
5386 } else if (ch
== '<') {
5387 ufoTibSkipCh(); // skip quote
5391 ufoFatal("expected quoted string");
5394 if (!ufoPop()) ufoFatal("file name expected");
5395 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5396 if (ufoTibPeekCh() != 0) {
5397 ufoFatal("$INCLUDE doesn't accept extra args yet");
5399 // ( addr count soft? system? -- )
5400 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
5404 //==========================================================================
5406 // ufoCreateFileGuard
5408 //==========================================================================
5409 static const char *ufoCreateFileGuard (const char *fname
) {
5410 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
5411 char *rp
= ufoRealPath(fname
);
5412 if (rp
== NULL
) return NULL
;
5414 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
5416 // hash the buffer; extract file name; create string with path len, file name, and hash
5417 const size_t orgplen
= strlen(rp
);
5418 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
5419 size_t plen
= orgplen
;
5420 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
5421 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5422 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
5423 return ufoRealPathHashBuf
;
5427 // $INCLUDE-ONCE "str"
5428 // includes file only once; unreliable on shitdoze, i believe
5429 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
5430 uint32_t softinclude
= 0, system
= 0;
5431 // parse include filename
5432 //UFCALL(PARSE_SKIP_BLANKS);
5433 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5434 uint8_t ch
= ufoTibPeekCh();
5436 ufoTibSkipCh(); // skip quote
5438 } else if (ch
== '<') {
5439 ufoTibSkipCh(); // skip quote
5443 ufoFatal("expected quoted string");
5446 if (!ufoPop()) ufoFatal("file name expected");
5447 const uint32_t count
= ufoPop();
5448 const uint32_t addr
= ufoPop();
5449 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5450 if (ufoTibPeekCh() != 0) {
5451 ufoFatal("$REQUIRE doesn't accept extra args yet");
5453 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5454 &system
, &softinclude
);
5455 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5456 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
5457 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5458 // this will overwrite `ufoRealPathHashBuf`
5459 const char *guard
= ufoCreateFileGuard(incfname
);
5461 if (guard
== NULL
) {
5462 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
5466 fprintf(stderr
, "GUARD: <%s>\n", guard
);
5468 // now check for the guard
5469 const uint32_t glen
= (uint32_t)strlen(guard
);
5470 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
5471 UForthCondDefine
*dd
;
5472 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5473 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
5474 // nothing to do: already included
5479 dd
= calloc(1, sizeof(UForthCondDefine
));
5480 if (dd
== NULL
) ufoFatal("out of memory for defines");
5481 dd
->name
= calloc(1, glen
+ 1u);
5482 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5483 strcpy(dd
->name
, guard
);
5486 dd
->next
= ufoCondDefines
;
5487 ufoCondDefines
= dd
;
5488 // ( addr count soft? system? -- )
5489 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
5490 UFCALL(PAR_INCLUDE
);
5494 // ////////////////////////////////////////////////////////////////////////// //
5500 UFWORD(PAR_NEW_HANDLE
) {
5501 const uint32_t typeid = ufoPop();
5502 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5503 UfoHandle
*hh
= ufoAllocHandle(typeid);
5504 ufoPush(hh
->ufoHandle
);
5509 UFWORD(PAR_FREE_HANDLE
) {
5510 const uint32_t hx
= ufoPop();
5512 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
5513 UfoHandle
*hh
= ufoGetHandle(hx
);
5514 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
5521 UFWORD(PAR_HANDLE_GET_TYPEID
) {
5522 const uint32_t hx
= ufoPop();
5523 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5524 UfoHandle
*hh
= ufoGetHandle(hx
);
5525 if (hh
== NULL
) ufoFatal("invalid handle");
5526 ufoPush(hh
->typeid);
5531 UFWORD(PAR_HANDLE_SET_TYPEID
) {
5532 const uint32_t hx
= ufoPop();
5533 const uint32_t typeid = ufoPop();
5534 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5535 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5536 UfoHandle
*hh
= ufoGetHandle(hx
);
5537 if (hh
== NULL
) ufoFatal("invalid handle");
5538 hh
->typeid = typeid;
5543 UFWORD(PAR_HANDLE_GET_SIZE
) {
5544 const uint32_t hx
= ufoPop();
5546 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5547 UfoHandle
*hh
= ufoGetHandle(hx
);
5548 if (hh
== NULL
) ufoFatal("invalid handle");
5557 UFWORD(PAR_HANDLE_SET_SIZE
) {
5558 const uint32_t hx
= ufoPop();
5559 const uint32_t size
= ufoPop();
5560 if (size
> 0x04000000) ufoFatal("invalid handle size");
5561 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5562 UfoHandle
*hh
= ufoGetHandle(hx
);
5563 if (hh
== NULL
) ufoFatal("invalid handle");
5564 if (hh
->size
!= size
) {
5569 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
5570 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
5572 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
5575 if (hh
->used
> size
) hh
->used
= size
;
5581 UFWORD(PAR_HANDLE_GET_USED
) {
5582 const uint32_t hx
= ufoPop();
5584 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5585 UfoHandle
*hh
= ufoGetHandle(hx
);
5586 if (hh
== NULL
) ufoFatal("invalid handle");
5595 UFWORD(PAR_HANDLE_SET_USED
) {
5596 const uint32_t hx
= ufoPop();
5597 const uint32_t used
= ufoPop();
5598 if (used
> 0x04000000) ufoFatal("invalid handle used");
5599 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5600 UfoHandle
*hh
= ufoGetHandle(hx
);
5601 if (hh
== NULL
) ufoFatal("invalid handle");
5602 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
5606 #define POP_PREPARE_HANDLE() \
5607 const uint32_t hx = ufoPop(); \
5608 uint32_t idx = ufoPop(); \
5609 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5610 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5611 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5612 UfoHandle *hh = ufoGetHandle(hx); \
5613 if (hh == NULL) ufoFatal("invalid handle")
5616 // ( idx hx -- value )
5617 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5618 POP_PREPARE_HANDLE();
5619 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5620 ufoPush(hh
->data
[idx
]);
5624 // ( idx hx -- value )
5625 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5626 POP_PREPARE_HANDLE();
5627 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5628 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5630 #ifdef UFO_FAST_MEM_ACCESS
5631 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5633 uint32_t res
= hh
->data
[idx
];
5634 res
|= hh
->data
[idx
+ 1u] << 8;
5640 // ( idx hx -- value )
5641 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5642 POP_PREPARE_HANDLE();
5643 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5644 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5646 #ifdef UFO_FAST_MEM_ACCESS
5647 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5649 uint32_t res
= hh
->data
[idx
];
5650 res
|= hh
->data
[idx
+ 1u] << 8;
5651 res
|= hh
->data
[idx
+ 2u] << 16;
5652 res
|= hh
->data
[idx
+ 3u] << 24;
5658 // ( value idx hx -- value )
5659 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5660 POP_PREPARE_HANDLE();
5661 const uint32_t value
= ufoPop();
5662 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5663 hh
->data
[idx
] = value
;
5667 // ( value idx hx -- )
5668 UFWORD(PAR_HANDLE_STORE_WORD
) {
5669 POP_PREPARE_HANDLE();
5670 const uint32_t value
= ufoPop();
5671 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5672 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5674 #ifdef UFO_FAST_MEM_ACCESS
5675 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5677 hh
->data
[idx
] = (uint8_t)value
;
5678 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5683 // ( value idx hx -- )
5684 UFWORD(PAR_HANDLE_STORE_CELL
) {
5685 POP_PREPARE_HANDLE();
5686 const uint32_t value
= ufoPop();
5687 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5688 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5690 #ifdef UFO_FAST_MEM_ACCESS
5691 *(uint32_t *)(hh
->data
+ idx
) = value
;
5693 hh
->data
[idx
] = (uint8_t)value
;
5694 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5695 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5696 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5702 // ( addr count -- stx / FALSE )
5703 UFWORD(PAR_HANDLE_LOAD_FILE
) {
5704 uint32_t count
= ufoPop();
5705 uint32_t addr
= ufoPop();
5707 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5709 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
5710 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
5711 uint8_t ch
= ufoImgGetU8Ext(addr
);
5713 dest
+= 1u; addr
+= 1u; count
-= 1u;
5715 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
5718 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
5720 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
5722 FILE *fl
= fopen(ffn
, "rb");
5724 FILE *fl
= fopen(ffn
, "r");
5732 if (fseek(fl
, 0, SEEK_END
) != 0) {
5734 ufoFatal("seek error in file '%s'", ffn
);
5737 long sz
= ftell(fl
);
5738 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
5740 ufoFatal("tell error in file '%s' (or too big)", ffn
);
5743 if (fseek(fl
, 0, SEEK_SET
) != 0) {
5745 ufoFatal("seek error in file '%s'", ffn
);
5748 UfoHandle
*hh
= ufoAllocHandle(0);
5750 hh
->data
= malloc((uint32_t)sz
);
5751 if (hh
->data
== NULL
) {
5753 ufoFatal("out of memory for file '%s'", ffn
);
5755 hh
->size
= (uint32_t)sz
;
5756 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
5758 ufoFatal("error reading file '%s'", ffn
);
5764 ufoPush(hh
->ufoHandle
);
5768 // ////////////////////////////////////////////////////////////////////////// //
5772 // DEBUG:(DECOMPILE-CFA)
5774 UFWORD(DEBUG_DECOMPILE_CFA
) {
5775 const uint32_t cfa
= ufoPop();
5777 ufoDecompileWord(cfa
);
5780 // DEBUG:(DECOMPILE-MEM)
5781 // ( addr-start addr-end -- )
5782 UFWORD(DEBUG_DECOMPILE_MEM
) {
5783 const uint32_t end
= ufoPop();
5784 const uint32_t start
= ufoPop();
5786 ufoDecompilePart(start
, end
, 0);
5792 ufoPush((uint32_t)ufo_get_msecs());
5795 // this is called by INTERPRET when it is out of input stream
5796 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
5802 UFWORD(MT_NEW_STATE
) {
5803 UfoState
*st
= ufoNewState();
5804 ufoInitStateUserVars(st
, ufoPop());
5810 UFWORD(MT_FREE_STATE
) {
5811 UfoState
*st
= ufoFindState(ufoPop());
5812 if (st
== NULL
) ufoFatal("cannot free unknown state");
5813 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5817 // MTASK:STATE-NAME@
5818 // ( stid -- addr count )
5820 UFWORD(MT_GET_STATE_NAME
) {
5821 UfoState
*st
= ufoFindState(ufoPop());
5822 if (st
== NULL
) ufoFatal("unknown state");
5824 uint32_t addr
= ufoPop();
5826 while (st
->name
[count
] != 0) {
5827 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5830 ufoImgPutU8Ext(addr
+ count
, 0);
5835 // MTASK:STATE-NAME!
5836 // ( addr count stid -- )
5837 UFWORD(MT_SET_STATE_NAME
) {
5838 UfoState
*st
= ufoFindState(ufoPop());
5839 if (st
== NULL
) ufoFatal("unknown state");
5840 uint32_t count
= ufoPop();
5841 uint32_t addr
= ufoPop();
5842 if ((count
& ((uint32_t)1 << 31)) == 0) {
5843 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5844 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5845 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5847 st
->name
[count
] = 0;
5851 // MTASK:STATE-FIRST
5853 UFWORD(MT_STATE_FIRST
) {
5855 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5856 // there should be at least one allocated state
5857 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5858 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5860 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5865 // ( stid -- stid / 0 )
5866 UFWORD(MT_STATE_NEXT
) {
5867 uint32_t stid
= ufoPop();
5868 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5869 // it is already incremented for us, yay!
5870 uint32_t fidx
= stid
/ 32u;
5871 uint8_t fofs
= stid
& 0x1f;
5872 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5873 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5875 while (fofs
!= 32u) {
5876 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5879 ufoPush(fidx
* 32u + fofs
+ 1u);
5883 fidx
+= 1u; fofs
= 0;
5891 // ( ... argc stid -- )
5892 UFWORD(MT_YIELD_TO
) {
5893 UfoState
*st
= ufoFindState(ufoPop());
5894 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5895 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5896 const uint32_t argc
= ufoPop();
5897 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
5898 UfoState
*curst
= ufoCurrState
;
5899 if (st
!= ufoCurrState
) {
5900 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
5901 ufoCurrState
= curst
;
5902 const uint32_t n
= ufoPop();
5906 ufoCurrState
= curst
; // we need to use API call to switch states
5908 ufoSwitchToState(st
); // always use API call for this!
5913 // MTASK:SET-SELF-AS-DEBUGGER
5915 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
5916 ufoDebuggerState
= ufoCurrState
;
5921 // debugger task receives debugge stid on the data stack, and -1 as argc.
5922 // i.e. debugger stask is: ( -1 old-stid )
5923 UFWORD(MT_DEBUGGER_BP
) {
5924 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
&& ufoIsGoodTTY()) {
5925 UfoState
*st
= ufoCurrState
;
5926 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
5931 UFCALL(UFO_BACKTRACE
);
5935 // MTASK:DEBUGGER-RESUME
5937 UFWORD(MT_RESUME_DEBUGEE
) {
5938 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5939 UfoState
*st
= ufoFindState(ufoPop());
5940 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5941 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5942 ufoSwitchToState(st
); // always use API call for this!
5946 // MTASK:DEBUGGER-SINGLE-STEP
5948 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
5949 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5950 UfoState
*st
= ufoFindState(ufoPop());
5951 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5952 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5953 ufoSwitchToState(st
); // always use API call for this!
5954 ufoSingleStep
= 2; // it will be decremented after returning from this word
5959 UFWORD(MT_STATE_IP_GET
) {
5960 UfoState
*st
= ufoFindState(ufoPop());
5961 if (st
== NULL
) ufoFatal("unknown state");
5967 UFWORD(MT_STATE_IP_SET
) {
5968 UfoState
*st
= ufoFindState(ufoPop());
5969 if (st
== NULL
) ufoFatal("unknown state");
5975 UFWORD(MT_STATE_REGA_GET
) {
5976 UfoState
*st
= ufoFindState(ufoPop());
5977 if (st
== NULL
) ufoFatal("unknown state");
5983 UFWORD(MT_STATE_REGA_SET
) {
5984 UfoState
*st
= ufoFindState(ufoPop());
5985 if (st
== NULL
) ufoFatal("unknown state");
5986 st
->regA
= ufoPop();
5989 // MTASK:STATE-USER@
5990 // ( addr stid -- value )
5991 UFWORD(MT_STATE_USER_GET
) {
5992 UfoState
*st
= ufoFindState(ufoPop());
5993 if (st
== NULL
) ufoFatal("unknown state");
5994 const uint32_t addr
= ufoPop();
5995 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
5996 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
5999 ufoFatal("invalid user area address");
6003 // MTASK:STATE-USER!
6004 // ( value addr stid -- )
6005 UFWORD(MT_STATE_USER_SET
) {
6006 UfoState
*st
= ufoFindState(ufoPop());
6007 if (st
== NULL
) ufoFatal("unknown state");
6008 const uint32_t addr
= ufoPop();
6009 const uint32_t value
= ufoPop();
6010 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
6011 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
6013 ufoFatal("invalid user area address");
6017 // MTASK:STATE-RPOPCFA@
6019 UFWORD(MT_STATE_RPOPCFA_GET
) {
6020 UfoState
*st
= ufoFindState(ufoPop());
6021 if (st
== NULL
) ufoFatal("unknown state");
6022 ufoPush(st
->vmRPopCFA
);
6025 // MTASK:STATE-RPOPCFA!
6027 UFWORD(MT_STATE_RPOPCFA_SET
) {
6028 UfoState
*st
= ufoFindState(ufoPop());
6029 if (st
== NULL
) ufoFatal("unknown state");
6030 st
->vmRPopCFA
= ufoPop();
6033 // MTASK:ACTIVE-STATE
6035 UFWORD(MT_ACTIVE_STATE
) {
6036 ufoPush(ufoCurrState
->id
);
6039 // MTASK:YIELDED-FROM
6041 UFWORD(MT_YIELDED_FROM
) {
6042 if (ufoYieldedState
!= NULL
) {
6043 ufoPush(ufoYieldedState
->id
);
6050 // ( stid -- depth )
6051 UFWORD(MT_DSTACK_DEPTH_GET
) {
6052 UfoState
*st
= ufoFindState(ufoPop());
6053 if (st
== NULL
) ufoFatal("unknown state");
6058 // ( stid -- depth )
6059 UFWORD(MT_RSTACK_DEPTH_GET
) {
6060 UfoState
*st
= ufoFindState(ufoPop());
6061 if (st
== NULL
) ufoFatal("unknown state");
6062 ufoPush(st
->RP
- st
->RPTop
);
6068 UfoState
*st
= ufoFindState(ufoPop());
6069 if (st
== NULL
) ufoFatal("unknown state");
6075 UFWORD(MT_LBP_GET
) {
6076 UfoState
*st
= ufoFindState(ufoPop());
6077 if (st
== NULL
) ufoFatal("unknown state");
6082 // ( depth stid -- )
6083 UFWORD(MT_DSTACK_DEPTH_SET
) {
6084 UfoState
*st
= ufoFindState(ufoPop());
6085 if (st
== NULL
) ufoFatal("unknown state");
6086 const uint32_t idx
= ufoPop();
6087 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
6092 // ( depth stid -- )
6093 UFWORD(MT_RSTACK_DEPTH_SET
) {
6094 UfoState
*st
= ufoFindState(ufoPop());
6095 if (st
== NULL
) ufoFatal("unknown state");
6096 const uint32_t idx
= ufoPop();
6097 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
6098 if (idx
>= left
) ufoFatal("invalid rstack index %u (%u)", idx
, left
);
6099 st
->RP
= st
->RPTop
+ idx
;
6105 UfoState
*st
= ufoFindState(ufoPop());
6106 if (st
== NULL
) ufoFatal("unknown state");
6112 UFWORD(MT_LBP_SET
) {
6113 UfoState
*st
= ufoFindState(ufoPop());
6114 if (st
== NULL
) ufoFatal("unknown state");
6119 // ( idx stid -- value )
6120 UFWORD(MT_DSTACK_LOAD
) {
6121 UfoState
*st
= ufoFindState(ufoPop());
6122 if (st
== NULL
) ufoFatal("unknown state");
6123 const uint32_t idx
= ufoPop();
6124 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6125 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
6129 // ( idx stid -- value )
6130 UFWORD(MT_RSTACK_LOAD
) {
6131 UfoState
*st
= ufoFindState(ufoPop());
6132 if (st
== NULL
) ufoFatal("unknown state");
6133 const uint32_t idx
= ufoPop();
6134 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6135 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
6139 // ( idx stid -- value )
6140 UFWORD(MT_LSTACK_LOAD
) {
6141 UfoState
*st
= ufoFindState(ufoPop());
6142 if (st
== NULL
) ufoFatal("unknown state");
6143 const uint32_t idx
= ufoPop();
6144 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
6145 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
6149 // ( value idx stid -- )
6150 UFWORD(MT_DSTACK_STORE
) {
6151 UfoState
*st
= ufoFindState(ufoPop());
6152 if (st
== NULL
) ufoFatal("unknown state");
6153 const uint32_t idx
= ufoPop();
6154 const uint32_t value
= ufoPop();
6155 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6156 st
->dStack
[st
->SP
- idx
- 1u] = value
;
6160 // ( value idx stid -- )
6161 UFWORD(MT_RSTACK_STORE
) {
6162 UfoState
*st
= ufoFindState(ufoPop());
6163 if (st
== NULL
) ufoFatal("unknown state");
6164 const uint32_t idx
= ufoPop();
6165 const uint32_t value
= ufoPop();
6166 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6167 st
->dStack
[st
->RP
- idx
- 1u] = value
;
6171 // ( value idx stid -- )
6172 UFWORD(MT_LSTACK_STORE
) {
6173 UfoState
*st
= ufoFindState(ufoPop());
6174 if (st
== NULL
) ufoFatal("unknown state");
6175 const uint32_t idx
= ufoPop();
6176 const uint32_t value
= ufoPop();
6177 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
6178 st
->dStack
[st
->LP
- idx
- 1u] = value
;
6182 #include "urforth_tty.c"
6185 // ////////////////////////////////////////////////////////////////////////// //
6189 static unsigned char ufoFileIOBuffer
[4096];
6192 //==========================================================================
6196 //==========================================================================
6197 static char *ufoPopFileName (void) {
6198 uint32_t count
= ufoPop();
6199 uint32_t addr
= ufoPop();
6201 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid file name");
6202 if (count
== 0) ufoFatal("empty file name");
6203 if (count
> (uint32_t)sizeof(ufoFNameBuf
) - 1u) ufoFatal("file name too long");
6205 unsigned char *dest
= (unsigned char *)ufoFNameBuf
;
6206 while (count
!= 0) {
6207 *dest
= ufoImgGetU8Ext(addr
);
6208 dest
+= 1u; addr
+= 1u; count
-= 1u;
6217 UFWORD(FILES_ERRNO
) {
6218 ufoPush((uint32_t)errno
);
6222 // ( addr count -- success? )
6223 UFWORD(FILES_UNLINK
) {
6224 const char *fname
= ufoPopFileName();
6225 ufoPushBool(unlink(fname
) == 0);
6229 // ( addr count -- handle TRUE / FALSE )
6230 UFWORD(FILES_OPEN_RO
) {
6231 const char *fname
= ufoPopFileName();
6232 const int fd
= open(fname
, O_RDONLY
);
6234 ufoPush((uint32_t)fd
);
6242 // ( addr count -- handle TRUE / FALSE )
6243 UFWORD(FILES_OPEN_RW
) {
6244 const char *fname
= ufoPopFileName();
6245 const int fd
= open(fname
, O_RDWR
);
6247 ufoPush((uint32_t)fd
);
6255 // ( addr count -- handle TRUE / FALSE )
6256 UFWORD(FILES_CREATE
) {
6257 const char *fname
= ufoPopFileName();
6258 //FIXME: add variable with default flags
6259 const int fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6261 ufoPush((uint32_t)fd
);
6269 // ( handle -- success? )
6270 UFWORD(FILES_CLOSE
) {
6271 const int32_t fd
= (int32_t)ufoPop();
6272 if (fd
< 0) ufoFatal("invalid file handle in 'CLOSE'");
6273 ufoPushBool(close(fd
) == 0);
6277 // ( handle -- ofs TRUE / FALSE )
6278 // `handle` cannot be 0.
6279 UFWORD(FILES_TELL
) {
6280 const int32_t fd
= (int32_t)ufoPop();
6281 if (fd
< 0) ufoFatal("invalid file handle in 'TELL'");
6282 const off_t pos
= lseek(fd
, 0, SEEK_CUR
);
6283 if (pos
!= (off_t
)-1) {
6284 ufoPush((uint32_t)pos
);
6292 // ( ofs whence handle -- TRUE / FALSE )
6293 // `handle` cannot be 0.
6294 UFWORD(FILES_SEEK_EX
) {
6295 const int32_t fd
= (int32_t)ufoPop();
6296 const uint32_t whence
= ufoPop();
6297 const uint32_t ofs
= ufoPop();
6298 if (fd
< 0) ufoFatal("invalid file handle in 'SEEK-EX'");
6299 if (whence
!= (uint32_t)SEEK_SET
&&
6300 whence
!= (uint32_t)SEEK_CUR
&&
6301 whence
!= (uint32_t)SEEK_END
) ufoFatal("invalid `whence` in 'SEEK-EX'");
6302 const off_t pos
= lseek(fd
, (off_t
)ofs
, (int)whence
);
6303 ufoPushBool(pos
!= (off_t
)-1);
6307 // ( handle -- size TRUE / FALSE )
6308 // `handle` cannot be 0.
6309 UFWORD(FILES_SIZE
) {
6310 const int32_t fd
= (int32_t)ufoPop();
6311 if (fd
< 0) ufoFatal("invalid file handle in 'SIZE'");
6312 const off_t origpos
= lseek(fd
, 0, SEEK_CUR
);
6313 if (origpos
== (off_t
)-1) {
6316 const off_t size
= lseek(fd
, 0, SEEK_END
);
6317 if (size
== (off_t
)-1) {
6318 (void)lseek(origpos
, 0, SEEK_SET
);
6320 } else if (lseek(origpos
, 0, SEEK_SET
) == origpos
) {
6321 ufoPush((uint32_t)size
);
6330 // ( addr count handle -- rdsize TRUE / FALSE )
6331 // `handle` cannot be 0.
6332 UFWORD(FILES_READ
) {
6333 const int32_t fd
= (int32_t)ufoPop();
6334 if (fd
< 0) ufoFatal("invalid file handle in 'READ'");
6335 uint32_t count
= ufoPop();
6336 uint32_t addr
= ufoPop();
6339 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6340 while (count
!= done
) {
6341 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6342 if (rd
> count
) rd
= count
;
6344 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6345 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6346 if (errno
== EINTR
) continue;
6347 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6354 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6355 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6365 // ( addr count handle -- TRUE / FALSE )
6366 // `handle` cannot be 0.
6367 UFWORD(FILES_READ_EXACT
) {
6368 const int32_t fd
= (int32_t)ufoPop();
6369 if (fd
< 0) ufoFatal("invalid file handle in 'READ-EXACT'");
6370 uint32_t count
= ufoPop();
6371 uint32_t addr
= ufoPop();
6373 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6374 while (count
!= 0) {
6375 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6376 if (rd
> count
) rd
= count
;
6378 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6379 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6380 if (errno
== EINTR
) continue;
6381 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6386 if (rd
== 0) { ufoPushBool(0); return; } // still error
6388 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6389 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6398 // ( addr count handle -- TRUE / FALSE )
6399 // `handle` cannot be 0.
6400 UFWORD(FILES_WRITE
) {
6401 const int32_t fd
= (int32_t)ufoPop();
6402 if (fd
< 0) ufoFatal("invalid file handle in 'WRITE'");
6403 uint32_t count
= ufoPop();
6404 uint32_t addr
= ufoPop();
6406 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to write to file");
6407 while (count
!= 0) {
6408 uint32_t wr
= (uint32_t)sizeof(ufoFileIOBuffer
);
6409 if (wr
> count
) wr
= count
;
6410 for (uint32_t f
= 0; f
!= wr
; f
+= 1u) {
6411 ufoFileIOBuffer
[f
] = ufoImgGetU8Ext(addr
+ f
);
6414 const ssize_t xres
= write(fd
, ufoFileIOBuffer
, wr
);
6415 if (xres
>= 0) { wr
= (uint32_t)xres
; break; }
6416 if (errno
== EINTR
) continue;
6417 fprintf(stderr
, "ERRNO: %d (fd=%d)\n", errno
, fd
);
6418 //if (errno == EAGAIN || errno == EWOULDBLOCK) { wr = 0; break; }
6423 if (wr
== 0) { ufoPushBool(1); return; } // still error
6424 count
-= wr
; addr
+= wr
;
6431 // ////////////////////////////////////////////////////////////////////////// //
6435 //==========================================================================
6439 // create a new state, its execution will start from the given CFA.
6440 // state is not automatically activated.
6442 //==========================================================================
6443 static UfoState
*ufoNewState (void) {
6444 // find free state id
6446 uint32_t bmp
= ufoStateUsedBitmap
[0];
6447 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
6449 bmp
= ufoStateUsedBitmap
[fidx
];
6451 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
6452 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6454 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
6455 ufo_assert(fidx
< UFO_MAX_STATES
);
6456 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
6457 ufo_assert(ufoStateMap
[fidx
] == NULL
);
6458 UfoState
*st
= calloc(1, sizeof(UfoState
));
6459 if (st
== NULL
) ufoFatal("out of memory for states");
6461 ufoStateMap
[fidx
] = st
;
6462 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
6463 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6468 //==========================================================================
6472 // free all memory used for the state, remove it from state list.
6473 // WARNING! never free current state!
6475 //==========================================================================
6476 static void ufoFreeState (UfoState
*st
) {
6478 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
6479 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
6480 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
6481 const uint32_t fidx
= st
->id
- 1u;
6482 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6483 ufo_assert(fidx
< UFO_MAX_STATES
);
6484 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
6485 ufo_assert(ufoStateMap
[fidx
] == st
);
6486 // free default TIB handle
6487 UfoState
*oldst
= ufoCurrState
;
6489 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
6490 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
6491 UfoHandle
*tibh
= ufoGetHandle(tib
);
6492 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
6494 ufoCurrState
= oldst
;
6496 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
6498 ufoStateMap
[fidx
] = NULL
;
6499 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
6504 //==========================================================================
6508 //==========================================================================
6509 static UfoState
*ufoFindState (uint32_t stid
) {
6510 UfoState
*res
= NULL
;
6511 if (stid
>= 0 && stid
<= UFO_MAX_STATES
) {
6514 ufo_assert(ufoCurrState
!= NULL
);
6515 stid
= ufoCurrState
->id
- 1u;
6519 res
= ufoStateMap
[stid
];
6521 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
6522 ufo_assert(res
->id
== stid
+ 1u);
6524 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
6531 //==========================================================================
6535 //==========================================================================
6536 static void ufoSwitchToState (UfoState
*newst
) {
6537 ufo_assert(newst
!= NULL
);
6538 if (newst
!= ufoCurrState
) {
6539 ufoCurrState
= newst
;
6544 // ////////////////////////////////////////////////////////////////////////// //
6545 // initial dictionary definitions
6550 #define UFWORD(name_) do { \
6551 const uint32_t xcfa_ = ufoCFAsUsed; \
6552 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6553 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6555 ufoDefineNative(""#name_, xcfa_, 0); \
6558 #define UFWORDX(strname_,name_) do { \
6559 const uint32_t xcfa_ = ufoCFAsUsed; \
6560 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6561 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6563 ufoDefineNative(strname_, xcfa_, 0); \
6566 #define UFWORD_IMM(name_) do { \
6567 const uint32_t xcfa_ = ufoCFAsUsed; \
6568 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6569 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6571 ufoDefineNative(""#name_, xcfa_, 1); \
6574 #define UFWORDX_IMM(strname_,name_) do { \
6575 const uint32_t xcfa_ = ufoCFAsUsed; \
6576 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6577 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6579 ufoDefineNative(strname_, xcfa_, 1); \
6582 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
6585 //==========================================================================
6587 // ufoFindWordChecked
6589 //==========================================================================
6590 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
6591 const uint32_t cfa
= ufoFindWord(wname
);
6592 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
6597 //==========================================================================
6601 // get "FORTH" vocid
6603 //==========================================================================
6604 uint32_t ufoGetForthVocId (void) {
6605 return ufoForthVocId
;
6609 //==========================================================================
6611 // ufoVocSetOnlyDefs
6613 //==========================================================================
6614 void ufoVocSetOnlyDefs (uint32_t vocid
) {
6615 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6616 ufoImgPutU32(ufoAddrContext
, vocid
);
6620 //==========================================================================
6624 // return voc PFA (vocid)
6626 //==========================================================================
6627 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
6628 // create wordlist struct
6629 // typeid, used by Forth code (structs and such)
6630 ufoImgEmitU32(0); // typeid
6631 // vocid points here, to "LATEST-LFA"
6632 const uint32_t vocid
= UFO_GET_DP();
6633 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
6634 ufoImgEmitU32(0); // latest
6635 const uint32_t vlink
= UFO_GET_DP();
6636 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
6637 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
6638 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
6643 ufoImgEmitU32(parentvocid
); // parent
6644 const uint32_t hdraddr
= UFO_GET_DP();
6645 ufoImgEmitU32(0); // word header
6646 // create empty hash table
6647 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
6648 // update CONTEXT and CURRENT if this is the first wordlist ever
6649 if (ufoImgGetU32(ufoAddrContext
) == 0) {
6650 ufoImgPutU32(ufoAddrContext
, vocid
);
6652 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
6653 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6655 // create word header
6656 if (wname
!= NULL
&& wname
[0] != 0) {
6658 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6660 //UFW_FLAG_IMMEDIATE|
6662 //UFW_FLAG_NORETURN|
6668 flags |= UFW_FLAG_VOCAB;
6670 flags
&= 0xffffff00u
;
6671 flags
|= UFW_FLAG_VOCAB
;
6672 ufoCreateWordHeader(wname
, flags
);
6673 const uint32_t cfa
= UFO_GET_DP();
6674 ufoImgEmitU32(ufoDoVocCFA
); // cfa
6675 ufoImgEmitU32(vocid
); // pfa
6676 // update vocab header pointer
6677 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
6678 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
6679 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6680 ufoDumpWordHeader(lfa
);
6687 //==========================================================================
6691 //==========================================================================
6692 static void ufoSetLatestArgs (uint32_t warg
) {
6693 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
6694 const uint32_t lfa
= ufoImgGetU32(curr
);
6695 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
6696 uint32_t flags
= ufoImgGetU32(nfa
);
6697 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
6698 flags
&= ~UFW_WARG_MASK
;
6699 flags
|= warg
& UFW_WARG_MASK
;
6700 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
6701 ufoImgPutU32(nfa
, flags
);
6702 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6703 ufoDumpWordHeader(lfa
);
6708 //==========================================================================
6712 //==========================================================================
6713 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
6714 cfaidx
|= UFO_ADDR_CFA_BIT
;
6715 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6717 //UFW_FLAG_IMMEDIATE|
6719 //UFW_FLAG_NORETURN|
6725 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
6726 ufoCreateWordHeader(wname
, flags
);
6727 ufoImgEmitU32(cfaidx
);
6731 //==========================================================================
6733 // ufoDefineConstant
6735 //==========================================================================
6736 static void ufoDefineConstant (const char *name
, uint32_t value
) {
6737 ufoDefineNative(name
, ufoDoConstCFA
, 0);
6738 ufoImgEmitU32(value
);
6742 //==========================================================================
6746 //==========================================================================
6747 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
6748 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
6749 ufoImgEmitU32(addr
);
6753 //==========================================================================
6757 //==========================================================================
6759 static void ufoDefineVar (const char *name, uint32_t value) {
6760 ufoDefineNative(name, ufoDoVarCFA, 0);
6761 ufoImgEmitU32(value);
6766 //==========================================================================
6770 //==========================================================================
6772 static void ufoDefineDefer (const char *name, uint32_t value) {
6773 ufoDefineNative(name, ufoDoDeferCFA, 0);
6774 ufoImgEmitU32(value);
6779 //==========================================================================
6783 //==========================================================================
6784 static void ufoHiddenWords (void) {
6785 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6786 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6790 //==========================================================================
6794 //==========================================================================
6795 static void ufoPublicWords (void) {
6796 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6797 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
6801 //==========================================================================
6805 //==========================================================================
6807 static void ufoDefineForth (const char *name) {
6808 ufoDefineNative(name, ufoDoForthCFA, 0);
6813 //==========================================================================
6815 // ufoDefineForthImm
6817 //==========================================================================
6819 static void ufoDefineForthImm (const char *name) {
6820 ufoDefineNative(name, ufoDoForthCFA, 1);
6825 //==========================================================================
6827 // ufoDefineForthHidden
6829 //==========================================================================
6831 static void ufoDefineForthHidden (const char *name) {
6832 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6833 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6834 ufoDefineNative(name, ufoDoForthCFA, 0);
6835 ufoImgPutU32(ufoAddrNewWordFlags, flags);
6840 //==========================================================================
6842 // ufoDefineSColonForth
6844 // create word suitable for scattered colon extension
6846 //==========================================================================
6847 static void ufoDefineSColonForth (const char *name
) {
6848 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6849 // placeholder for scattered colon
6850 // it will compile two branches:
6851 // the first branch will jump to the first "..:" word (or over the two branches)
6852 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
6853 // this way, each extension word will simply fix the last branch address, and update list tail
6854 // at the creation time, second branch points to the first branch
6855 UFC("FORTH:(BRANCH)");
6856 const uint32_t xjmp
= UFO_GET_DP();
6858 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
6859 ufoImgPutU32(xjmp
, UFO_GET_DP());
6863 //==========================================================================
6867 //==========================================================================
6868 UFO_FORCE_INLINE
void ufoDoneForth (void) {
6869 UFC("FORTH:(EXIT)");
6873 //==========================================================================
6877 // compile string literal, the same as QUOTE_IMM
6879 //==========================================================================
6880 static void ufoCompileStrLitEx (const char *str
, const uint32_t slen
) {
6881 if (str
== NULL
) str
= "";
6882 if (slen
> 255) ufoFatal("string literal too long");
6883 UFC("FORTH:(LITSTR8)");
6884 ufoImgEmitU8((uint8_t)slen
);
6885 for (size_t f
= 0; f
< slen
; f
+= 1) {
6886 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
6893 //==========================================================================
6897 //==========================================================================
6899 static void ufoCompileStrLit (const char *str) {
6900 ufoCompileStrLitEx(str, (uint32_t)strlen(str));
6905 //==========================================================================
6909 //==========================================================================
6910 static void ufoCompileLit (uint32_t value
) {
6912 ufoImgEmitU32(value
);
6916 //==========================================================================
6920 //==========================================================================
6922 static void ufoCompileCFALit (const char *wname) {
6923 UFC("FORTH:(LITCFA)");
6924 const uint32_t cfa = ufoFindWordChecked(wname);
6930 //==========================================================================
6934 //==========================================================================
6935 static int ufoXStrEquCI (const char *word
, const char *text
, uint32_t tlen
) {
6936 while (tlen
!= 0 && *word
) {
6937 if (toUpper(*word
) != toUpper(*text
)) return 0;
6938 word
+= 1u; text
+= 1u; tlen
-= 1u;
6940 return (tlen
== 0 && *word
== 0);
6944 #define UFO_MAX_LABEL_NAME (63)
6945 typedef struct UfoLabel_t
{
6948 char name
[UFO_MAX_LABEL_NAME
];
6949 uint32_t addr
; // jump chain tail, or address
6951 uint32_t word
; // is this a forward word definition?
6952 struct UfoLabel_t
*next
;
6955 static UfoLabel
*ufoLabels
= NULL
;
6958 //==========================================================================
6960 // ufoFindAddLabelEx
6962 //==========================================================================
6963 static UfoLabel
*ufoFindAddLabelEx (const char *name
, uint32_t namelen
, int allowAdd
) {
6964 if (namelen
== 0 || namelen
> UFO_MAX_LABEL_NAME
) ufoFatal("invalid label name");
6965 const uint32_t hash
= joaatHashBufCI(name
, namelen
);
6966 UfoLabel
*lbl
= ufoLabels
;
6967 while (lbl
!= NULL
) {
6968 if (lbl
->hash
== hash
&& lbl
->namelen
== namelen
) {
6971 while (ok
&& sidx
!= namelen
) {
6972 ok
= (toUpper(name
[sidx
]) == toUpper(lbl
->name
[sidx
]));
6981 lbl
= calloc(1, sizeof(UfoLabel
));
6983 lbl
->namelen
= namelen
;
6984 memcpy(lbl
->name
, name
, namelen
);
6985 lbl
->name
[namelen
] = 0;
6986 lbl
->next
= ufoLabels
;
6995 //==========================================================================
6999 //==========================================================================
7000 static UfoLabel
*ufoFindAddLabel (const char *name
, uint32_t namelen
) {
7001 return ufoFindAddLabelEx(name
, namelen
, 1);
7005 //==========================================================================
7009 //==========================================================================
7010 static UfoLabel
*ufoFindLabel (const char *name
, uint32_t namelen
) {
7011 return ufoFindAddLabelEx(name
, namelen
, 0);
7015 //==========================================================================
7017 // ufoTrySimpleNumber
7019 // only decimal and C-like hexes; with an optional sign
7021 //==========================================================================
7022 static int ufoTrySimpleNumber (const char *text
, uint32_t tlen
, uint32_t *num
) {
7025 if (tlen
!= 0 && *text
== '+') { text
+= 1u; tlen
-= 1u; }
7026 else if (tlen
!= 0 && *text
== '-') { neg
= 1; text
+= 1u; tlen
-= 1u; }
7028 int base
= 10; // default base
7029 if (tlen
> 2 && text
[0] == '0' && toUpper(text
[1]) == 'X') {
7032 text
+= 2u; tlen
-= 2u;
7035 if (tlen
== 0 || digitInBase(*text
, base
) < 0) return 0;
7042 if (!wasDigit
) return 0;
7045 dig
= digitInBase(*text
, base
);
7046 if (dig
< 0) return 0;
7048 n
= n
* (uint32_t)base
+ (uint32_t)dig
;
7050 text
+= 1u; tlen
-= 1u;
7053 if (!wasDigit
) return 0;
7054 if (neg
) n
= ~n
+ 1u;
7060 //==========================================================================
7062 // ufoEmitLabelChain
7064 //==========================================================================
7065 static void ufoEmitLabelChain (UfoLabel
*lbl
) {
7066 ufo_assert(lbl
!= NULL
);
7067 ufo_assert(lbl
->defined
== 0);
7068 const uint32_t here
= UFO_GET_DP();
7069 ufoImgEmitU32(lbl
->addr
);
7074 //==========================================================================
7076 // ufoFixLabelChainHere
7078 //==========================================================================
7079 static void ufoFixLabelChainHere (UfoLabel
*lbl
) {
7080 ufo_assert(lbl
!= NULL
);
7081 ufo_assert(lbl
->defined
== 0);
7082 const uint32_t here
= UFO_GET_DP();
7083 while (lbl
->addr
!= 0) {
7084 const uint32_t aprev
= ufoImgGetU32(lbl
->addr
);
7085 ufoImgPutU32(lbl
->addr
, here
);
7093 #define UFO_MII_WORD_COMPILE_IMM (-4)
7094 #define UFO_MII_WORD_CFA_LIT (-3)
7095 #define UFO_MII_WORD_COMPILE (-2)
7096 #define UFO_MII_IN_WORD (-1)
7097 #define UFO_MII_NO_WORD (0)
7098 #define UFO_MII_WORD_NAME (1)
7099 #define UFO_MII_WORD_NAME_IMM (2)
7100 #define UFO_MII_WORD_NAME_HIDDEN (3)
7102 static int ufoMinInterpState
= UFO_MII_NO_WORD
;
7105 //==========================================================================
7107 // ufoFinalLabelCheck
7109 //==========================================================================
7110 static void ufoFinalLabelCheck (void) {
7112 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) {
7113 ufoFatal("missing semicolon");
7115 while (ufoLabels
!= NULL
) {
7116 UfoLabel
*lbl
= ufoLabels
; ufoLabels
= lbl
->next
;
7117 if (!lbl
->defined
) {
7118 fprintf(stderr
, "UFO ERROR: label '%s' is not defined!\n", lbl
->name
);
7123 if (errorCount
!= 0) {
7124 ufoFatal("%d undefined label%s", errorCount
, (errorCount
!= 1 ? "s" : ""));
7129 //==========================================================================
7133 // this is so i could write Forth definitions more easily
7136 // $name -- reference
7137 // $name: -- definition
7139 //==========================================================================
7140 UFO_DISABLE_INLINE
void ufoInterpretLine (const char *line
) {
7141 char wname
[UFO_MAX_WORD_LENGTH
];
7142 uint32_t wlen
, num
, cfa
;
7145 if (*(const unsigned char *)line
<= 32) {
7147 } else if (ufoMinInterpState
== UFO_MII_WORD_CFA_LIT
||
7148 ufoMinInterpState
== UFO_MII_WORD_COMPILE
||
7149 ufoMinInterpState
== UFO_MII_WORD_COMPILE_IMM
)
7151 // "[']"/"COMPILE"/"[COMPILE]" argument
7153 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7154 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7155 memcpy(wname
, line
, wlen
);
7157 switch (ufoMinInterpState
) {
7158 case UFO_MII_WORD_CFA_LIT
: UFC("FORTH:(LITCFA)"); break;
7159 case UFO_MII_WORD_COMPILE
: UFC("FORTH:(LITCFA)"); break;
7160 case UFO_MII_WORD_COMPILE_IMM
: break;
7161 default: ufo_assert(0);
7163 cfa
= ufoFindWord(wname
);
7167 // forward reference
7168 lbl
= ufoFindAddLabel(line
, wlen
);
7169 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7170 ufoFatal("unknown word: '%s'", wname
);
7173 ufoEmitLabelChain(lbl
);
7175 switch (ufoMinInterpState
) {
7176 case UFO_MII_WORD_CFA_LIT
: break;
7177 case UFO_MII_WORD_COMPILE
: UFC("FORTH:COMPILE,"); break;
7178 case UFO_MII_WORD_COMPILE_IMM
: break;
7179 default: ufo_assert(0);
7181 ufoMinInterpState
= UFO_MII_IN_WORD
;
7183 } else if (ufoMinInterpState
> UFO_MII_NO_WORD
) {
7186 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7187 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7188 if (wlen
> 2 && line
[0] == ':' && line
[wlen
- 1u] == ':') ufoFatal("invalid word name");
7189 memcpy(wname
, line
, wlen
);
7191 const uint32_t oldFlags
= ufoImgGetU32(ufoAddrNewWordFlags
);
7192 if (ufoMinInterpState
== UFO_MII_WORD_NAME_HIDDEN
) {
7193 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
| UFW_FLAG_HIDDEN
);
7195 ufoDefineNative(wname
, ufoDoForthCFA
, (ufoMinInterpState
== UFO_MII_WORD_NAME_IMM
));
7196 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
);
7197 ufoMinInterpState
= UFO_MII_IN_WORD
;
7198 // check for forward references
7199 lbl
= ufoFindLabel(line
, wlen
);
7201 if (lbl
->defined
|| !lbl
->word
) {
7202 ufoFatal("label/word conflict for '%.*s'", (unsigned)wlen
, line
);
7204 ufoFixLabelChainHere(lbl
);
7207 } else if ((line
[0] == ';' && line
[1] == ';') ||
7208 (line
[0] == '-' && line
[1] == '-') ||
7209 (line
[0] == '/' && line
[1] == '/') ||
7210 (line
[0] == '\\' && ((const unsigned char *)line
)[1] <= 32))
7212 ufoFatal("do not use single-line comments");
7213 } else if (line
[0] == '(' && ((const unsigned char *)line
)[1] <= 32) {
7214 while (*line
&& *line
!= ')') line
+= 1;
7215 if (*line
== ')') line
+= 1;
7219 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7220 if (wlen
== 1 && (line
[0] == '"' || line
[0] == '`')) {
7222 const char qch
= line
[0];
7223 if (!line
[1]) ufoFatal("unterminated string literal");
7224 // skip quote and space
7225 if (((const unsigned char *)line
)[1] <= 32) line
+= 2u; else line
+= 1u;
7227 while (line
[wlen
] && line
[wlen
] != qch
) wlen
+= 1u;
7228 if (line
[wlen
] != qch
) ufoFatal("unterminated string literal");
7229 ufoCompileStrLitEx(line
, wlen
);
7230 line
+= wlen
+ 1u; // skip final quote
7231 } else if (wlen
== 1 && line
[0] == ':') {
7233 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7234 ufoMinInterpState
= UFO_MII_WORD_NAME
;
7236 } else if (wlen
== 1 && line
[0] == ';') {
7238 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected semicolon");
7239 ufoImgEmitU32(ufoFindWordChecked("FORTH:(EXIT)"));
7240 ufoMinInterpState
= UFO_MII_NO_WORD
;
7242 } else if (wlen
== 2 && line
[0] == '!' && line
[1] == ':') {
7243 // new immediate word
7244 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7245 ufoMinInterpState
= UFO_MII_WORD_NAME_IMM
;
7247 } else if (wlen
== 2 && line
[0] == '*' && line
[1] == ':') {
7249 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7250 ufoMinInterpState
= UFO_MII_WORD_NAME_HIDDEN
;
7252 } else if (wlen
== 3 && memcmp(line
, "[']", 3) == 0) {
7254 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7255 ufoMinInterpState
= UFO_MII_WORD_CFA_LIT
;
7257 } else if (wlen
== 7 && ufoXStrEquCI("COMPILE", line
, wlen
)) {
7259 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7260 ufoMinInterpState
= UFO_MII_WORD_COMPILE
;
7262 } else if (wlen
== 9 && ufoXStrEquCI("[COMPILE]", line
, wlen
)) {
7264 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7265 ufoMinInterpState
= UFO_MII_WORD_COMPILE_IMM
;
7269 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7270 memcpy(wname
, line
, wlen
);
7272 cfa
= ufoFindWord(wname
);
7276 } else if (ufoTrySimpleNumber(line
, wlen
, &num
)) {
7277 // compile numeric literal
7280 // unknown word, this may be a forward reference, or a label definition
7281 // label defintion starts with "$"
7282 // (there are no words starting with "$" in the initial image)
7283 if (line
[0] == '$') {
7284 if (wlen
== 1) ufoFatal("dollar what?");
7285 if (wlen
> 2 && line
[wlen
- 1u] == ':') {
7287 lbl
= ufoFindAddLabel(line
, wlen
- 1u);
7288 if (lbl
->defined
) ufoFatal("double label '%s' definition", lbl
->name
);
7289 ufoFixLabelChainHere(lbl
);
7292 lbl
= ufoFindAddLabel(line
, wlen
);
7294 ufoImgEmitU32(lbl
->addr
);
7296 ufoEmitLabelChain(lbl
);
7300 // forward reference
7301 lbl
= ufoFindAddLabel(line
, wlen
);
7302 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7303 ufoFatal("unknown word: '%s'", wname
);
7306 ufoEmitLabelChain(lbl
);
7316 //==========================================================================
7320 //==========================================================================
7321 UFO_DISABLE_INLINE
void ufoReset (void) {
7322 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
7324 ufoSP
= 0; ufoRP
= 0;
7325 ufoLP
= 0; ufoLBP
= 0;
7328 ufoVMStop
= 0; ufoVMAbort
= 0;
7333 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
7334 const uint32_t tibDef
= ufoImgGetU32(ufoAddrDefTIB
);
7335 ufoInitStateUserVars(ufoCurrState
, 0);
7337 ufoImgPutU32(ufoAddrTIBx
, tib
);
7338 ufoImgPutU32(ufoAddrDefTIB
, tibDef
);
7339 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
7342 ufoImgPutU32(ufoAddrDPTemp
, 0);
7344 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
7345 ufoVocSetOnlyDefs(ufoForthVocId
);
7349 //==========================================================================
7351 // ufoDefineEmitType
7353 //==========================================================================
7354 UFO_DISABLE_INLINE
void ufoDefineEmitType (void) {
7357 ufoInterpretLine(": EMIT ( ch -- ) (NORM-EMIT-CHAR) (EMIT) ;");
7361 ufoInterpretLine(": XEMIT ( ch -- ) (NORM-XEMIT-CHAR) (EMIT) ;");
7365 ufoInterpretLine(": CR ( -- ) NL (EMIT) ;");
7371 " LASTCR? FORTH:(TBRANCH) $endcr-exit CR "
7374 //ufoDecompileWord(ufoFindWordChecked("ENDCR"));
7378 ufoInterpretLine(": SPACE ( -- ) BL (EMIT) ;");
7383 ": SPACES ( count -- ) "
7385 " DUP 0> FORTH:(0BRANCH) $spaces-exit "
7387 " FORTH:(BRANCH) $spaces-again "
7393 // ( addr count -- )
7395 ": TYPE ( addr count -- ) "
7398 " DUP 0> FORTH:(0BRANCH) $type-exit "
7401 " FORTH:(BRANCH) $type-again "
7407 // ( addr count -- )
7409 ": XTYPE ( addr count -- ) "
7412 " DUP 0> FORTH:(0BRANCH) $xtype-exit "
7415 " FORTH:(BRANCH) $xtype-again "
7423 ": HERE ( -- here ) "
7424 " FORTH:(DP-TEMP) @ ?DUP "
7425 " FORTH:(TBRANCH) $here-exit "
7433 ": ALIGN-HERE ( -- ) "
7434 "$align-here-loop: "
7436 " FORTH:(0BRANCH) $align-here-exit "
7438 " FORTH:(BRANCH) $align-here-loop "
7439 "$align-here-exit: "
7443 // ( C:addr count -- ) ( E: -- addr count )
7445 ": STRLITERAL ( C:addr count -- ) ( E: -- addr count ) "
7446 " DUP 255 U> ` string literal too long` ?ERROR "
7447 " STATE @ FORTH:(0BRANCH) $strlit-exit "
7449 " ['] FORTH:(LITSTR8) COMPILE, "
7451 " ( compile length ) "
7453 " ( compile chars ) "
7455 " DUP 0<> FORTH:(0BRANCH) $strlit-loop-exit "
7457 " FORTH:(BRANCH) $strlit-loop "
7458 "$strlit-loop-exit: "
7460 " ( final 0: our counter is 0 here, so use it ) "
7466 // ( -- addr count )
7468 "!: \" ( -- addr count ) "
7469 " 34 PARSE ` string literal expected` ?NOT-ERROR "
7470 " COMPILER:(UNESCAPE) STRLITERAL "
7475 //==========================================================================
7477 // ufoDefineInterpret
7479 // define "INTERPRET" in Forth
7481 //==========================================================================
7482 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
7483 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
7485 // return "stop flag"
7487 "*: (UFO-INTERPRET-NEXT-LINE) ( -- continue? ) "
7488 " STATE @ FORTH:(TBRANCH) $ipn_incomp "
7489 " ( interpreter allowed to cross include boundary ) "
7490 " REFILL FORTH:(BRANCH) $ipn_done "
7492 " ( compiler is not allowed to cross include boundary ) "
7493 " REFILL-NOCROSS ` compiler cannot cross file boundaries` ?NOT-ERROR "
7498 ufoInterpNextLineCFA
= ufoFindWordChecked("FORTH:(UFO-INTERPRET-NEXT-LINE)");
7499 ufoInterpretLine("*: (INTERPRET-NEXT-LINE) (USER-INTERPRET-NEXT-LINE) @ EXECUTE-TAIL ;");
7501 // skip comments, parse name, refilling lines if necessary
7502 // returning FALSE as counter means: "no addr, exit INTERPRET"
7504 "*: (INTERPRET-PARSE-NAME) ( -- addr count / FALSE ) "
7505 "$label_ipn_again: "
7506 " TRUE (PARSE-SKIP-COMMENTS) PARSE-NAME "
7507 " DUP FORTH:(TBRANCH) $label_ipn_exit_fwd "
7508 " 2DROP (INTERPRET-NEXT-LINE) "
7509 " FORTH:(TBRANCH) $label_ipn_again "
7511 "$label_ipn_exit_fwd: "
7513 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
7518 " FORTH:(INTERPRET-PARSE-NAME) ( addr count / FALSE )"
7519 " ?DUP FORTH:(0BRANCH) $interp-done "
7520 " ( try defered checker ) "
7521 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7522 " FALSE (INTERPRET-CHECK-WORD) FORTH:(TBRANCH) $interp-again "
7523 " 2DUP FIND-WORD ( addr count cfa TRUE / addr count FALSE ) "
7524 " FORTH:(0BRANCH) $interp-try-number "
7526 " NROT 2DROP ( drop word string ) "
7527 " STATE @ FORTH:(0BRANCH) $interp-exec "
7528 " ( compiling; check immediate bit ) "
7529 " DUP CFA->NFA @ COMPILER:(WFLAG-IMMEDIATE) AND FORTH:(TBRANCH) $interp-exec "
7531 " FORTH:COMPILE, FORTH:(BRANCH) $interp-again "
7534 " EXECUTE FORTH:(BRANCH) $interp-again "
7535 " ( not a word, try a number ) "
7536 "$interp-try-number: "
7537 " 2DUP TRUE BASE @ (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE ) "
7538 " FORTH:(0BRANCH) $interp-number-error "
7540 " NROT 2DROP ( drop word string ) "
7541 " ( do we need to compile it? ) "
7542 " STATE @ FORTH:(0BRANCH) $interp-again "
7543 " COMPILE FORTH:(LIT) FORTH:, "
7544 " FORTH:(BRANCH) $interp-again "
7546 "$interp-number-error: "
7547 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7548 " FALSE (INTERPRET-WORD-NOT-FOUND) FORTH:(TBRANCH) $interp-again "
7549 " ENDCR SPACE XTYPE ` -- wut?` TYPE CR "
7550 " ` unknown word` ERROR "
7553 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
7557 //==========================================================================
7561 //==========================================================================
7562 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
7563 uint32_t imgAddr
= 0;
7565 // reserve 32 bytes for nothing
7566 for (uint32_t f
= 0; f
< 32; f
+= 1) {
7567 ufoImgPutU8(imgAddr
, 0);
7571 while ((imgAddr
& 3) != 0) {
7572 ufoImgPutU8(imgAddr
, 0);
7577 ufoAddrDP
= imgAddr
;
7578 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7581 ufoAddrDPTemp
= imgAddr
;
7582 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7585 ufoAddrLastXFA
= imgAddr
;
7586 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7589 ufoAddrVocLink
= imgAddr
;
7590 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7593 ufoAddrNewWordFlags
= imgAddr
;
7594 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
7596 // WORD-REDEFINE-WARN-MODE
7597 ufoAddrRedefineWarning
= imgAddr
;
7598 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
7600 // setup (DP) and (DP-TEMP)
7601 ufoImgPutU32(ufoAddrDP
, imgAddr
);
7602 ufoImgPutU32(ufoAddrDPTemp
, 0);
7605 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
7610 //==========================================================================
7612 // ufoInitStateUserVars
7614 //==========================================================================
7615 static void ufoInitStateUserVars (UfoState
*st
, uint32_t cfa
) {
7616 ufo_assert(st
!= NULL
);
7617 if (st
->imageTempSize
< 8192u) {
7618 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
7619 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
7620 st
->imageTemp
= itmp
;
7621 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
7622 st
->imageTempSize
= 8192;
7624 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
7625 st
->imageTemp
[(ufoAddrSTATE
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7626 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
7627 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7628 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7629 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7630 st
->imageTemp
[(ufoAddrContext
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7631 st
->imageTemp
[(ufoAddrCurrent
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7632 st
->imageTemp
[(ufoAddrSelf
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7633 st
->imageTemp
[(ufoAddrInterNextLine
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoInterpNextLineCFA
;
7634 st
->imageTemp
[(ufoAddrEP
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7635 // init other things, because this procedure is used in `ufoReset()` too
7636 st
->SP
= 0; st
->RP
= 0; st
->RPTop
= 0; st
->regA
= 0;
7637 st
->LP
= 0; st
->LBP
= 0; st
->vmRPopCFA
= 0;
7642 st
->rStack
[0] = 0xdeadf00d; // dummy value
7643 st
->rStack
[1] = cfa
;
7649 //==========================================================================
7651 // ufoInitBasicWords
7653 //==========================================================================
7654 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
7655 ufoDefineConstant("FALSE", 0);
7656 ufoDefineConstant("TRUE", ufoTrueValue
);
7658 ufoDefineConstant("BL", 32);
7659 ufoDefineConstant("NL", 10);
7662 ufoDefineUserVar("BASE", ufoAddrBASE
);
7663 ufoDefineUserVar("TIB", ufoAddrTIBx
);
7664 ufoDefineUserVar(">IN", ufoAddrINx
);
7665 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
7666 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
7667 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
7668 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
7669 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
7670 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
7672 ufoDefineUserVar("STATE", ufoAddrSTATE
);
7673 ufoDefineConstant("CONTEXT", ufoAddrContext
);
7674 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
7675 ufoDefineConstant("(SELF)", ufoAddrSelf
); // used in OOP implementations
7676 ufoDefineConstant("(USER-INTERPRET-NEXT-LINE)", ufoAddrInterNextLine
);
7677 ufoDefineConstant("(EXC-FRAME-PTR)", ufoAddrEP
);
7680 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
7681 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
7682 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
7683 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
7684 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
7685 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
7686 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
7688 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
7689 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
7690 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
7692 ufoDefineConstant("(DP)", ufoAddrDP
);
7693 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
7696 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
7697 UFWORDX("SP0!", SP0_STORE
);
7698 UFWORDX("RP0!", RP0_STORE
);
7700 UFWORDX("PAD", PAD
);
7703 UFWORDX("C@", CPEEK
);
7704 UFWORDX("W@", WPEEK
);
7707 UFWORDX("C!", CPOKE
);
7708 UFWORDX("W!", WPOKE
);
7710 UFWORDX(",", COMMA
);
7711 UFWORDX("C,", CCOMMA
);
7712 UFWORDX("W,", WCOMMA
);
7714 UFWORDX("A>", REGA_LOAD
);
7715 UFWORDX(">A", REGA_STORE
);
7716 UFWORDX("A-SWAP", REGA_SWAP
);
7717 UFWORDX("+1>A", REGA_INC
);
7718 UFWORDX("+4>A", REGA_INC_CELL
);
7719 UFWORDX("A>R", REGA_TO_R
);
7720 UFWORDX("R>A", R_TO_REGA
);
7722 UFWORDX("@A+", PEEK_REGA_IDX
);
7723 UFWORDX("C@A+", CPEEK_REGA_IDX
);
7724 UFWORDX("W@A+", WPEEK_REGA_IDX
);
7726 UFWORDX("!A+", POKE_REGA_IDX
);
7727 UFWORDX("C!A+", CPOKE_REGA_IDX
);
7728 UFWORDX("W!A+", WPOKE_REGA_IDX
);
7731 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
7732 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
7733 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
7734 UFWORDX("(LITSTR8)", PAR_LITSTR8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
7735 UFWORDX("(EXIT)", PAR_EXIT
);
7737 ufoLitStr8CFA
= ufoFindWordChecked("FORTH:(LITSTR8)");
7739 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
7740 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
7741 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
7742 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
7744 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7745 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7746 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7747 UFWORDX("(+0BRANCH)", PAR_P0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7748 UFWORDX("(+BRANCH)", PAR_PBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7749 UFWORDX("(-0BRANCH)", PAR_M0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7750 UFWORDX("(-BRANCH)", PAR_MBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7751 UFWORDX("(DATASKIP)", PAR_DATASKIP
); ufoSetLatestArgs(UFW_WARG_DATASKIP
);
7756 //==========================================================================
7758 // ufoInitBasicCompilerWords
7760 //==========================================================================
7761 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
7762 // create "COMPILER" vocabulary
7763 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
7764 ufoVocSetOnlyDefs(ufoCompilerVocId
);
7766 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
7767 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
7768 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
7769 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
7770 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
7771 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
7772 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
7773 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
7775 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
7776 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
7777 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
7778 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
7779 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
7780 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
7781 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
7782 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
7784 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
7785 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
7786 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
7787 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
7788 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
7789 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
7790 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
7791 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
7792 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
7794 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
7795 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
7796 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
7797 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
7798 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
7799 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
7800 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
7802 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
7803 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
7804 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
7805 ufoDefineConstant("(REDEFINE-WARN-PARENTS)", UFO_REDEF_WARN_PARENTS
);
7807 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
7809 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
7813 " FORTH:STATE FORTH:@ ` expecting interpretation mode` FORTH:?ERROR "
7818 " FORTH:STATE FORTH:@ ` expecting compilation mode` FORTH:?NOT-ERROR "
7821 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
7822 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
7824 ufoVocSetOnlyDefs(ufoForthVocId
);
7827 ufoInterpretLine("!: [ COMPILER:?COMP 0 STATE ! ;");
7829 ufoInterpretLine(": ] COMPILER:?EXEC 1 STATE ! ;");
7833 //==========================================================================
7837 //==========================================================================
7838 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
7839 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
7841 UFWORDX("CFA->PFA", CFA2PFA
);
7842 UFWORDX("CFA->NFA", CFA2NFA
);
7843 UFWORDX("CFA->LFA", CFA2LFA
);
7844 UFWORDX("CFA->WEND", CFA2WEND
);
7846 UFWORDX("PFA->CFA", PFA2CFA
);
7847 UFWORDX("PFA->NFA", PFA2NFA
);
7849 UFWORDX("NFA->CFA", NFA2CFA
);
7850 UFWORDX("NFA->PFA", NFA2PFA
);
7851 UFWORDX("NFA->LFA", NFA2LFA
);
7853 UFWORDX("LFA->CFA", LFA2CFA
);
7854 UFWORDX("LFA->PFA", LFA2PFA
);
7855 UFWORDX("LFA->BFA", LFA2BFA
);
7856 UFWORDX("LFA->XFA", LFA2XFA
);
7857 UFWORDX("LFA->YFA", LFA2YFA
);
7858 UFWORDX("LFA->NFA", LFA2NFA
);
7860 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
7861 UFWORDX("FIND-WORD", FIND_WORD
);
7862 UFWORDX("(FIND-WORD-IN-VOC)", FIND_WORD_IN_VOC
);
7863 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", FIND_WORD_IN_VOC_AND_PARENTS
);
7866 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
7869 UFWORDX("?DUP", QDUP
);
7870 UFWORDX("2DUP", DDUP
);
7872 UFWORDX("2DROP", DDROP
);
7874 UFWORDX("2SWAP", DSWAP
);
7876 UFWORDX("2OVER", DOVER
);
7879 UFWORDX("PICK", PICK
);
7880 UFWORDX("ROLL", ROLL
);
7884 UFWORDX(">R", DTOR
);
7885 UFWORDX("R>", RTOD
);
7886 UFWORDX("R@", RPEEK
);
7887 UFWORDX("RPICK", RPICK
);
7888 UFWORDX("RROLL", RROLL
);
7889 UFWORDX("RSWAP", RSWAP
);
7890 UFWORDX("ROVER", ROVER
);
7891 UFWORDX("RROT", RROT
);
7892 UFWORDX("RNROT", RNROT
);
7894 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
7895 UFWORDX("(EMIT)", PAR_EMIT
);
7896 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR
);
7897 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR
);
7898 UFWORDX("LASTCR?", LASTCRQ
);
7899 UFWORDX("LASTCR!", LASTCRSET
);
7903 UFWORDX("-", MINUS
);
7905 UFWORDX("U*", UMUL
);
7907 UFWORDX("U/", UDIV
);
7908 UFWORDX("MOD", MOD
);
7909 UFWORDX("UMOD", UMOD
);
7910 UFWORDX("/MOD", DIVMOD
);
7911 UFWORDX("U/MOD", UDIVMOD
);
7912 UFWORDX("*/", MULDIV
);
7913 UFWORDX("U*/", UMULDIV
);
7914 UFWORDX("*/MOD", MULDIVMOD
);
7915 UFWORDX("U*/MOD", UMULDIVMOD
);
7916 UFWORDX("M*", MMUL
);
7917 UFWORDX("UM*", UMMUL
);
7918 UFWORDX("M/MOD", MDIVMOD
);
7919 UFWORDX("UM/MOD", UMDIVMOD
);
7920 UFWORDX("UDS*", UDSMUL
);
7922 UFWORDX("SM/REM", SMREM
);
7923 UFWORDX("FM/MOD", FMMOD
);
7925 UFWORDX("D-", DMINUS
);
7926 UFWORDX("D+", DPLUS
);
7927 UFWORDX("D=", DEQU
);
7928 UFWORDX("D<", DLESS
);
7929 UFWORDX("D<=", DLESSEQU
);
7930 UFWORDX("DU<", DULESS
);
7931 UFWORDX("DU<=", DULESSEQU
);
7938 UFWORDX(">", GREAT
);
7939 UFWORDX("<=", LESSEQU
);
7940 UFWORDX(">=", GREATEQU
);
7941 UFWORDX("U<", ULESS
);
7942 UFWORDX("U>", UGREAT
);
7943 UFWORDX("U<=", ULESSEQU
);
7944 UFWORDX("U>=", UGREATEQU
);
7946 UFWORDX("<>", NOTEQU
);
7948 UFWORDX("0=", ZERO_EQU
);
7949 UFWORDX("0<>", ZERO_NOTEQU
);
7951 UFWORDX("NOT", ZERO_EQU
);
7952 UFWORDX("NOTNOT", ZERO_NOTEQU
);
7958 UFWORDX("LOGAND", LOGAND
);
7959 UFWORDX("LOGOR", LOGOR
);
7962 UFWORDX("(TIB-IN)", TIB_IN
);
7963 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
7964 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
7965 UFWORDX("TIB-GETCH", TIB_GETCH
);
7966 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
7968 UFWORDX("REFILL", REFILL
);
7969 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
7972 UFWORDX("(PARSE)", PAR_PARSE
);
7973 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
7975 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
7976 UFWORDX("PARSE-NAME", PARSE_NAME
);
7977 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
7978 UFWORDX("PARSE", PARSE
);
7981 UFWORDX("(VSP@)", PAR_GET_VSP
);
7982 UFWORDX("(VSP!)", PAR_SET_VSP
);
7983 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
7984 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
7985 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
7987 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
7988 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
7989 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
7992 UFWORDX("ERROR", ERROR
);
7993 UFWORDX("FATAL-ERROR", ERROR
);
7995 ufoInterpretLine(": 1+ ( n -- n+1 ) 1 + ;");
7996 ufoInterpretLine(": 1- ( n -- n-1 ) 1 - ;");
7997 ufoInterpretLine(": 2+ ( n -- n+2 ) 2 + ;");
7998 ufoInterpretLine(": 2- ( n -- n-2 ) 2 - ;");
7999 ufoInterpretLine(": 4+ ( n -- n+4 ) 4 + ;");
8000 ufoInterpretLine(": 4- ( n -- n-4 ) 4 - ;");
8002 ufoInterpretLine(": 2* ( n -- n*2 ) 1 ASH ;");
8003 ufoInterpretLine(": 2/ ( n -- n/2 ) -1 ASH ;");
8004 ufoInterpretLine(": 4* ( n -- n*4 ) 2 ASH ;");
8005 ufoInterpretLine(": 4/ ( n -- n/4 ) -2 ASH ;");
8007 ufoInterpretLine(": 2U* ( u -- u*2 ) 1 LSH ;");
8008 ufoInterpretLine(": 2U/ ( u -- u/2 ) -1 LSH ;");
8009 ufoInterpretLine(": 4U* ( u -- u*4 ) 2 LSH ;");
8010 ufoInterpretLine(": 4U/ ( u -- u/4 ) -2 LSH ;");
8012 ufoInterpretLine(": 0< ( n -- n<0 ) 0 < ;");
8013 ufoInterpretLine(": 0> ( n -- n>0 ) 0 > ;");
8014 ufoInterpretLine(": 0<= ( n -- n<0 ) 0 <= ;");
8015 ufoInterpretLine(": 0>= ( n -- n>0 ) 0 >= ;");
8017 ufoInterpretLine(": @A ( idx -- v ) 0 @A+ ;");
8018 ufoInterpretLine(": C@A ( idx -- v ) 0 C@A+ ;");
8019 ufoInterpretLine(": W@A ( idx -- v ) 0 W@A+ ;");
8021 ufoInterpretLine(": !A ( idx -- v ) 0 !A+ ;");
8022 ufoInterpretLine(": C!A ( idx -- v ) 0 C!A+ ;");
8023 ufoInterpretLine(": W!A ( idx -- v ) 0 W!A+ ;");
8027 ufoInterpretLine(": ABORT ` \"ABORT\" called` ERROR ;");
8030 // ( errflag addr count -- )
8032 ": ?ERROR ( errflag addr count -- ) "
8033 " ROT FORTH:(0BRANCH) $qerr_skip ERROR "
8039 // ( errflag addr count -- )
8041 ": ?NOT-ERROR ( errflag addr count -- ) "
8042 " ROT FORTH:(TBRANCH) $qnoterr_skip ERROR "
8048 ": FIND-WORD-IN-VOC ( vocid addr count -- cfa TRUE / FALSE ) "
8049 " 0 (FIND-WORD-IN-VOC) ;");
8052 ": FIND-WORD-IN-VOC-AND-PARENTS ( vocid addr count -- cfa TRUE / FALSE ) "
8053 " 0 (FIND-WORD-IN-VOC-AND-PARENTS) ;");
8055 UFWORDX("GET-MSECS", GET_MSECS
);
8059 //==========================================================================
8061 // ufoInitHandleWords
8063 //==========================================================================
8064 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
8065 // create "HANDLE" vocabulary
8066 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
8067 ufoVocSetOnlyDefs(handleVocId
);
8068 UFWORDX("NEW", PAR_NEW_HANDLE
);
8069 UFWORDX("FREE", PAR_FREE_HANDLE
);
8070 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
8071 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
8072 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
8073 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
8074 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
8075 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
8076 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
8077 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
8078 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
8079 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
8080 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
8081 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
8082 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
8083 ufoVocSetOnlyDefs(ufoForthVocId
);
8087 //==========================================================================
8089 // ufoInitHigherWords
8091 //==========================================================================
8092 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
8093 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
8095 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
8096 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
8097 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
8098 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
8100 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
8101 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
8102 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
8104 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
8105 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
8109 //==========================================================================
8111 // ufoInitStringWords
8113 //==========================================================================
8114 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
8115 // create "STRING" vocabulary
8116 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
8117 ufoVocSetOnlyDefs(stringVocId
);
8118 UFWORDX("=", STREQU
);
8119 UFWORDX("=CI", STREQUCI
);
8120 UFWORDX("SEARCH", SEARCH
);
8121 UFWORDX("HASH", STRHASH
);
8122 UFWORDX("HASH-CI", STRHASHCI
);
8123 ufoVocSetOnlyDefs(ufoForthVocId
);
8127 //==========================================================================
8129 // ufoInitDebugWords
8131 //==========================================================================
8132 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
8133 // create "DEBUG" vocabulary
8134 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
8135 ufoVocSetOnlyDefs(debugVocId
);
8136 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
8137 UFWORDX("(DECOMPILE-MEM)", DEBUG_DECOMPILE_MEM
);
8138 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
8139 UFWORDX("DUMP-STACK", DUMP_STACK
);
8140 UFWORDX("BACKTRACE-TASK", UFO_BACKTRACE_TASK
);
8141 UFWORDX("DUMP-STACK-TASK", DUMP_STACK_TASK
);
8142 UFWORDX("DUMP-RSTACK-TASK", DUMP_RSTACK_TASK
);
8143 UFWORDX("(BP)", MT_DEBUGGER_BP
);
8144 UFWORDX("IP->NFA", IP2NFA
);
8145 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
8146 UFWORDX("IP->FILE-HASH/LINE", IP2FILEHASHLINE
);
8147 ufoVocSetOnlyDefs(ufoForthVocId
);
8151 //==========================================================================
8155 //==========================================================================
8156 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
8157 // create "MTASK" vocabulary
8158 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
8159 ufoVocSetOnlyDefs(mtVocId
);
8160 UFWORDX("NEW-STATE", MT_NEW_STATE
);
8161 UFWORDX("FREE-STATE", MT_FREE_STATE
);
8162 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
8163 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
8164 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
8165 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
8166 UFWORDX("YIELD-TO", MT_YIELD_TO
);
8167 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
8168 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
8169 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
8170 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
8171 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
8172 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
8173 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
8174 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
8175 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
8176 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
8177 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
8178 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
8179 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
8180 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
8181 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
8182 UFWORDX("STATE-LP@", MT_LP_GET
);
8183 UFWORDX("STATE-LBP@", MT_LBP_GET
);
8184 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
8185 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
8186 UFWORDX("STATE-LP!", MT_LP_SET
);
8187 UFWORDX("STATE-LBP!", MT_LBP_SET
);
8188 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
8189 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
8190 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
8191 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
8192 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
8193 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
8194 ufoVocSetOnlyDefs(ufoForthVocId
);
8198 //==========================================================================
8202 //==========================================================================
8203 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
8204 // create "TTY" vocabulary
8205 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
8206 ufoVocSetOnlyDefs(ttyVocId
);
8207 UFWORDX("TTY?", TTY_TTYQ
);
8208 UFWORDX("RAW?", TTY_RAWQ
);
8209 UFWORDX("SIZE", TTY_SIZE
);
8210 UFWORDX("SET-RAW", TTY_SET_RAW
);
8211 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
8212 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
8213 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
8214 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
8215 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
8216 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
8217 ufoVocSetOnlyDefs(ufoForthVocId
);
8221 //==========================================================================
8223 // ufoInitFilesWords
8225 //==========================================================================
8226 UFO_DISABLE_INLINE
void ufoInitFilesWords (void) {
8227 // create "FILES" vocabulary
8228 const uint32_t filesVocId
= ufoCreateVoc("FILES", 0, UFW_FLAG_PROTECTED
);
8229 ufoVocSetOnlyDefs(filesVocId
);
8230 ufoDefineConstant("SEEK-SET", SEEK_SET
);
8231 ufoDefineConstant("SEEK-CUR", SEEK_CUR
);
8232 ufoDefineConstant("SEEK-END", SEEK_END
);
8234 UFWORDX("OPEN-R/O", FILES_OPEN_RO
);
8235 UFWORDX("OPEN-R/W", FILES_OPEN_RW
);
8236 UFWORDX("CREATE", FILES_CREATE
);
8237 UFWORDX("CLOSE", FILES_CLOSE
);
8238 UFWORDX("TELL", FILES_TELL
);
8239 UFWORDX("SEEK-EX", FILES_SEEK_EX
);
8240 UFWORDX("SIZE", FILES_SIZE
);
8241 UFWORDX("READ", FILES_READ
);
8242 UFWORDX("READ-EXACT", FILES_READ_EXACT
);
8243 UFWORDX("WRITE", FILES_WRITE
);
8245 UFWORDX("UNLINK", FILES_UNLINK
);
8247 UFWORDX("ERRNO", FILES_ERRNO
);
8250 ": SEEK ( ofs handle -- success? ) "
8251 " SEEK-SET FORTH:SWAP SEEK-EX "
8256 ": READ-EXACT ( addr count handle -- success? ) "
8257 " FORTH:OVER FORTH:>R ( save count ) "
8258 " READ FORTH:DUP FORTH:(0BRANCH) $files-read-exact-error "
8259 " FORTH:DROP ( drop TRUE ) FORTH:R@ = "
8260 "$files-read-exact-error: "
8265 ufoVocSetOnlyDefs(ufoForthVocId
);
8269 //==========================================================================
8271 // ufoInitVeryVeryHighWords
8273 //==========================================================================
8274 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
8276 //ufoDefineDefer("INTERPRET", idumbCFA);
8278 ufoDefineEmitType();
8280 // ( addr count FALSE -- addr count FALSE / TRUE )
8281 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
8283 // ( addr count FALSE -- addr count FALSE / TRUE )
8284 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
8286 // ( -- ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
8287 ufoDefineSColonForth("(EXIT-EXTENDER)");
8291 ufoInterpretLine("!: EXIT ( -- ) COMPILER:?COMP (EXIT-EXTENDER) COMPILE FORTH:(EXIT) ;");
8293 ufoDefineInterpret();
8295 //ufoDumpVocab(ufoCompilerVocId);
8298 ": RUN-INTERPRET-LOOP "
8299 "$run-interp-loop-again: "
8300 " RP0! INTERPRET (UFO-INTERPRET-FINISHED-ACTION) "
8301 " FORTH:(BRANCH) $run-interp-loop-again "
8305 #define UFO_ADD_DO_CFA(cfx_) do { \
8306 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
8307 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
8312 //==========================================================================
8316 //==========================================================================
8317 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
8319 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
8321 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
8323 // allocate default TIB handle
8324 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
8325 //ufoDefTIB = tibh->ufoHandle;
8327 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
8328 UFO_ADD_DO_CFA(Forth
);
8329 UFO_ADD_DO_CFA(Variable
);
8330 UFO_ADD_DO_CFA(Value
);
8331 UFO_ADD_DO_CFA(Const
);
8332 UFO_ADD_DO_CFA(Defer
);
8333 UFO_ADD_DO_CFA(Voc
);
8334 UFO_ADD_DO_CFA(Create
);
8335 UFO_ADD_DO_CFA(UserVariable
);
8337 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
8341 // create "FORTH" vocabulary (it should be the first one)
8342 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
8343 ufoVocSetOnlyDefs(ufoForthVocId
);
8345 // base low-level interpreter words
8346 ufoInitBasicWords();
8351 // some COMPILER words
8352 ufoInitBasicCompilerWords();
8354 // STRING vocabulary
8355 ufoInitStringWords();
8358 ufoInitDebugWords();
8363 // HANDLE vocabulary
8364 ufoInitHandleWords();
8370 ufoInitFilesWords();
8372 // some higher-level FORTH words (includes, etc.)
8373 ufoInitHigherWords();
8375 // very-very high-level FORTH words
8376 ufoInitVeryVeryHighWords();
8378 ufoFinalLabelCheck();
8381 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
8390 // ////////////////////////////////////////////////////////////////////////// //
8391 // virtual machine executor
8395 //==========================================================================
8399 // address interpreter
8401 //==========================================================================
8402 static void ufoRunVMCFA (uint32_t cfa
) {
8403 const uint32_t oldRPTop
= ufoRPTop
;
8405 #ifdef UFO_TRACE_VM_RUN
8406 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
8412 // VM execution loop
8414 if (ufoVMAbort
) ufoFatal("user abort");
8415 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
8416 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
8417 if (ufoVMRPopCFA
== 0) {
8419 if (ufoIP
== 0) ufoFatal("IP is NULL");
8420 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
8421 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
8423 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
8426 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
8427 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
8428 // get next word CFAIDX, and check it
8429 uint32_t cfaidx
= ufoImgGetU32(cfa
);
8430 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
8431 #ifdef UFO_TRACE_VM_RUN
8432 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
8434 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
8435 fprintf(stderr
, "######################################\n");
8437 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
8438 cfaidx
&= UFO_ADDR_CFA_MASK
;
8439 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
8440 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
8441 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
8443 #ifdef UFO_TRACE_VM_RUN
8444 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
8445 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
8447 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
8449 // if CFA points somewhere inside a dict, this is "DOES>" word
8450 // IP points to PFA we need to push
8451 // CFA points to Forth word we need to jump to
8452 #ifdef UFO_TRACE_VM_DOER
8453 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
8454 UFCALL(UFO_BACKTRACE
);
8456 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
8457 ufoRPush(ufoIP
); // push IP
8458 ufoIP
= cfaidx
; // fix IP
8460 // that's all we need to activate the debugger
8461 if (ufoSingleStep
) {
8463 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
8464 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
8465 UfoState
*ost
= ufoCurrState
;
8466 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
8471 } while (ufoRP
!= oldRPTop
);
8476 // ////////////////////////////////////////////////////////////////////////// //
8480 //==========================================================================
8484 // register new word
8486 //==========================================================================
8487 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
8488 ufo_assert(cfa
!= NULL
);
8489 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8490 uint32_t cfaidx
= ufoCFAsUsed
;
8491 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
8492 ufoForthCFAs
[cfaidx
] = cfa
;
8494 //ufoDefineNative(wname, xcfa, 0);
8495 cfaidx
|= UFO_ADDR_CFA_BIT
;
8496 flags
&= 0xffffff00u
;
8497 ufoCreateWordHeader(wname
, flags
);
8498 const uint32_t res
= UFO_GET_DP();
8499 ufoImgEmitU32(cfaidx
);
8504 //==========================================================================
8506 // ufoRegisterDataWord
8508 //==========================================================================
8509 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
8512 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8513 flags
&= 0xffffff00u
;
8514 ufoCreateWordHeader(wname
, flags
);
8515 ufoImgEmitU32(cfaidx
);
8516 const uint32_t res
= UFO_GET_DP();
8517 ufoImgEmitU32(value
);
8522 //==========================================================================
8524 // ufoRegisterConstant
8526 //==========================================================================
8527 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
8528 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
8532 //==========================================================================
8534 // ufoRegisterVariable
8536 //==========================================================================
8537 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
8538 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
8542 //==========================================================================
8546 //==========================================================================
8547 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
8548 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
8552 //==========================================================================
8556 //==========================================================================
8557 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
8558 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
8562 //==========================================================================
8564 // ufoFindWordInVocabulary
8566 // check if we have the corresponding word.
8567 // return CFA suitable for executing, or 0.
8569 //==========================================================================
8570 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
8571 if (wname
== NULL
|| wname
[0] == 0) return 0;
8572 size_t wlen
= strlen(wname
);
8573 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
8574 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
8578 //==========================================================================
8582 //==========================================================================
8583 uint32_t ufoGetIP (void) {
8588 //==========================================================================
8592 //==========================================================================
8593 void ufoSetIP (uint32_t newip
) {
8598 //==========================================================================
8602 //==========================================================================
8603 int ufoIsExecuting (void) {
8604 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
8608 //==========================================================================
8612 //==========================================================================
8613 int ufoIsCompiling (void) {
8614 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
8618 //==========================================================================
8622 //==========================================================================
8623 void ufoSetExecuting (void) {
8624 ufoImgPutU32(ufoAddrSTATE
, 0);
8628 //==========================================================================
8632 //==========================================================================
8633 void ufoSetCompiling (void) {
8634 ufoImgPutU32(ufoAddrSTATE
, 1);
8638 //==========================================================================
8642 //==========================================================================
8643 uint32_t ufoGetHere () {
8644 return UFO_GET_DP();
8648 //==========================================================================
8652 //==========================================================================
8653 uint32_t ufoGetPad () {
8659 //==========================================================================
8663 //==========================================================================
8664 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
8665 return ufoTibPeekChOfs(ofs
);
8669 //==========================================================================
8673 //==========================================================================
8674 uint8_t ufoTIBGetCh (void) {
8675 return ufoTibGetCh();
8679 //==========================================================================
8683 //==========================================================================
8684 void ufoTIBSkipCh (void) {
8689 //==========================================================================
8695 //==========================================================================
8696 int ufoTIBSRefill (int allowCrossIncludes
) {
8697 return ufoLoadNextLine(allowCrossIncludes
);
8701 //==========================================================================
8705 //==========================================================================
8706 uint32_t ufoPeekData (void) {
8711 //==========================================================================
8715 //==========================================================================
8716 uint32_t ufoPopData (void) {
8721 //==========================================================================
8725 //==========================================================================
8726 void ufoPushData (uint32_t value
) {
8727 return ufoPush(value
);
8731 //==========================================================================
8735 //==========================================================================
8736 void ufoPushBoolData (int val
) {
8741 //==========================================================================
8745 //==========================================================================
8746 uint32_t ufoPeekRet (void) {
8751 //==========================================================================
8755 //==========================================================================
8756 uint32_t ufoPopRet (void) {
8761 //==========================================================================
8765 //==========================================================================
8766 void ufoPushRet (uint32_t value
) {
8767 return ufoRPush(value
);
8771 //==========================================================================
8775 //==========================================================================
8776 void ufoPushBoolRet (int val
) {
8777 ufoRPush(val
? ufoTrueValue
: 0);
8781 //==========================================================================
8785 //==========================================================================
8786 uint8_t ufoPeekByte (uint32_t addr
) {
8787 return ufoImgGetU8Ext(addr
);
8791 //==========================================================================
8795 //==========================================================================
8796 uint16_t ufoPeekWord (uint32_t addr
) {
8803 //==========================================================================
8807 //==========================================================================
8808 uint32_t ufoPeekCell (uint32_t addr
) {
8815 //==========================================================================
8819 //==========================================================================
8820 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
8821 ufoImgPutU8(addr
, value
);
8825 //==========================================================================
8829 //==========================================================================
8830 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
8837 //==========================================================================
8841 //==========================================================================
8842 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
8849 //==========================================================================
8853 //==========================================================================
8854 uint32_t ufoGetPAD (void) {
8855 return UFO_PAD_ADDR
;
8859 //==========================================================================
8863 //==========================================================================
8864 void ufoEmitByte (uint32_t value
) {
8865 ufoImgEmitU8(value
);
8869 //==========================================================================
8873 //==========================================================================
8874 void ufoEmitWord (uint32_t value
) {
8875 ufoImgEmitU8(value
& 0xff);
8876 ufoImgEmitU8((value
>> 8) & 0xff);
8880 //==========================================================================
8884 //==========================================================================
8885 void ufoEmitCell (uint32_t value
) {
8886 ufoImgEmitU32(value
);
8890 //==========================================================================
8894 //==========================================================================
8895 int ufoIsInited (void) {
8896 return (ufoMode
!= UFO_MODE_NONE
);
8900 static void (*ufoUserPostInitCB
) (void);
8903 //==========================================================================
8905 // ufoSetUserPostInit
8907 // called after main initialisation
8909 //==========================================================================
8910 void ufoSetUserPostInit (void (*cb
) (void)) {
8911 ufoUserPostInitCB
= cb
;
8915 //==========================================================================
8919 //==========================================================================
8920 void ufoInit (void) {
8921 if (ufoMode
!= UFO_MODE_NONE
) return;
8922 ufoMode
= UFO_MODE_NATIVE
;
8925 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
8927 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
8929 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
8930 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
8932 ufoCurrState
= ufoNewState();
8933 strcpy(ufoCurrState
->name
, "MAIN");
8934 ufoInitStateUserVars(ufoCurrState
, 0);
8935 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
8936 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
8938 ufoYieldedState
= NULL
;
8939 ufoDebuggerState
= NULL
;
8942 #ifdef UFO_DEBUG_STARTUP_TIMES
8943 uint32_t stt
= ufo_get_msecs();
8944 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
8947 #ifdef UFO_DEBUG_STARTUP_TIMES
8948 uint32_t ett
= ufo_get_msecs();
8949 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
8954 if (ufoUserPostInitCB
) {
8955 ufoUserPostInitCB();
8960 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
8962 FILE *ufl
= fopen(ufmname
, "rb");
8964 FILE *ufl
= fopen(ufmname
, "r");
8968 ufoSetInFileNameReuse(ufmname
);
8970 ufoFileId
= ufoLastUsedFileId
;
8971 setLastIncPath(ufoInFileName
, 1);
8974 ufoFatal("cannot load init code");
8977 if (ufoInFile
!= NULL
) {
8978 ufoRunInterpretLoop();
8983 //==========================================================================
8987 //==========================================================================
8988 void ufoFinishVM (void) {
8993 //==========================================================================
8997 // check if VM was exited due to `ufoFinishVM()`
8999 //==========================================================================
9000 int ufoWasVMFinished (void) {
9001 return (ufoVMStop
!= 0);
9005 //==========================================================================
9009 // ( -- addr count TRUE / FALSE )
9010 // does base TIB parsing; never copies anything.
9011 // as our reader is line-based, returns FALSE on EOL.
9012 // EOL is detected after skipping leading delimiters.
9013 // passing -1 as delimiter skips the whole line, and always returns FALSE.
9014 // trailing delimiter is always skipped.
9015 // result is on the data stack.
9017 //==========================================================================
9018 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
9019 ufoPush(delim
); ufoPushBool(skipLeading
);
9023 //==========================================================================
9027 // ( -- addr count )
9028 // parse with leading blanks skipping. doesn't copy anything.
9029 // return empty string on EOL.
9031 //==========================================================================
9032 void ufoCallParseName (void) {
9037 //==========================================================================
9041 // ( -- addr count TRUE / FALSE )
9042 // parse without skipping delimiters; never copies anything.
9043 // as our reader is line-based, returns FALSE on EOL.
9044 // passing 0 as delimiter skips the whole line, and always returns FALSE.
9045 // trailing delimiter is always skipped.
9047 //==========================================================================
9048 void ufoCallParse (uint32_t delim
) {
9054 //==========================================================================
9056 // ufoCallParseSkipBlanks
9058 //==========================================================================
9059 void ufoCallParseSkipBlanks (void) {
9060 UFCALL(PARSE_SKIP_BLANKS
);
9064 //==========================================================================
9066 // ufoCallParseSkipComments
9068 //==========================================================================
9069 void ufoCallParseSkipComments (void) {
9070 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9074 //==========================================================================
9076 // ufoCallParseSkipLineComments
9078 //==========================================================================
9079 void ufoCallParseSkipLineComments (void) {
9080 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9084 //==========================================================================
9086 // ufoCallParseSkipLine
9088 // to the end of line; doesn't refill
9090 //==========================================================================
9091 void ufoCallParseSkipLine (void) {
9092 UFCALL(PARSE_SKIP_LINE
);
9096 //==========================================================================
9098 // ufoCallBasedNumber
9100 // convert number from addrl+1
9101 // returns address of the first inconvertible char
9102 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
9104 //==========================================================================
9105 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
9106 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
9107 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
9108 UFCALL(PAR_BASED_NUMBER
);
9112 //==========================================================================
9116 //==========================================================================
9117 void ufoRunWord (uint32_t cfa
) {
9119 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9120 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9121 ufoMode
= UFO_MODE_NATIVE
;
9129 //==========================================================================
9133 //==========================================================================
9134 void ufoRunMacroWord (uint32_t cfa
) {
9136 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9137 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9138 ufoMode
= UFO_MODE_MACRO
;
9139 const uint32_t oisp
= ufoFileStackPos
;
9142 (void)ufoLoadNextUserLine();
9147 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
9152 //==========================================================================
9156 // check if we are currently in "MACRO" mode.
9157 // should be called from registered words.
9159 //==========================================================================
9160 int ufoIsInMacroMode (void) {
9161 return (ufoMode
== UFO_MODE_MACRO
);
9165 //==========================================================================
9167 // ufoRunInterpretLoop
9169 // run default interpret loop.
9171 //==========================================================================
9172 void ufoRunInterpretLoop (void) {
9173 if (ufoMode
== UFO_MODE_NONE
) {
9176 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
9177 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
9179 ufoMode
= UFO_MODE_NATIVE
;
9183 while (ufoFileStackPos
!= 0) ufoPopInFile();
9187 //==========================================================================
9191 //==========================================================================
9192 void ufoRunFile (const char *fname
) {
9193 if (ufoMode
== UFO_MODE_NONE
) {
9196 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
9197 ufoMode
= UFO_MODE_NATIVE
;
9200 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
9202 FILE *ufl
= fopen(ufmname
, "rb");
9204 FILE *ufl
= fopen(ufmname
, "r");
9208 ufoSetInFileNameReuse(ufmname
);
9210 ufoFileId
= ufoLastUsedFileId
;
9211 setLastIncPath(ufoInFileName
, 0);
9214 ufoFatal("cannot load source file '%s'", fname
);
9216 ufoRunInterpretLoop();