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;
502 static long ufoCurrIncludeLineFileOfs
= 0;
504 // dynamic memory handles
505 typedef struct UHandleInfo_t
{
512 struct UHandleInfo_t
*next
;
515 static UfoHandle
*ufoHandleFreeList
= NULL
;
516 static UfoHandle
**ufoHandles
= NULL
;
517 static uint32_t ufoHandlesUsed
= 0;
518 static uint32_t ufoHandlesAlloted
= 0;
520 #define UFO_HANDLE_FREE (~(uint32_t)0)
522 static char ufoCurrFileLine
[520];
525 static uint32_t ufoInBacktrace
= 0;
528 // ////////////////////////////////////////////////////////////////////////// //
529 static void ufoClearCondDefines (void);
531 static void ufoRunVMCFA (uint32_t cfa
);
533 static void ufoBacktrace (uint32_t ip
, int showDataStack
);
535 static void ufoClearCondDefines (void);
537 static UfoState
*ufoNewState (void);
538 static void ufoInitStateUserVars (UfoState
*st
, uint32_t cfa
);
539 static void ufoFreeState (UfoState
*st
);
540 static UfoState
*ufoFindState (uint32_t stid
);
541 static void ufoSwitchToState (UfoState
*newst
);
543 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
546 static void ufoDisableRaw (void);
548 static void ufoTTYRawFlush (void);
549 static int ufoIsGoodTTY (void);
551 #ifdef UFO_DEBUG_DEBUG
552 static void ufoDumpDebugImage (void);
556 // ////////////////////////////////////////////////////////////////////////// //
557 #define UFWORD(name_) \
558 static void ufoWord_##name_ (uint32_t mypfa)
560 #define UFCALL(name_) ufoWord_##name_(0)
561 #define UFCFA(name_) (&ufoWord_##name_)
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) {
586 //==========================================================================
590 // if `reuse` is not 0, reuse/free `fname`
592 //==========================================================================
593 static void ufoSetInFileNameEx (const char *fname
, int reuse
) {
594 ufo_assert(fname
== NULL
|| (fname
!= ufoInFileName
));
595 if (fname
== NULL
|| fname
[0] == 0) {
596 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
597 ufoInFileNameLen
= 0;
598 ufoInFileNameHash
= 0;
599 if (reuse
&& fname
!= NULL
) free((void *)fname
);
601 const uint32_t fnlen
= (uint32_t)strlen(fname
);
602 const uint32_t fnhash
= joaatHashBuf(fname
, fnlen
, 0);
603 if (ufoInFileNameLen
!= fnlen
|| ufoInFileNameHash
!= fnhash
) {
604 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
606 ufoInFileName
= (char *)fname
;
608 ufoInFileName
= strdup(fname
);
609 if (ufoInFileName
== NULL
) ufoFatal("out of memory for filename info");
611 ufoInFileNameLen
= fnlen
;
612 ufoInFileNameHash
= fnhash
;
614 if (reuse
&& fname
!= NULL
) free((void *)fname
);
620 //==========================================================================
624 //==========================================================================
625 UFO_FORCE_INLINE
void ufoSetInFileName (const char *fname
) {
626 ufoSetInFileNameEx(fname
, 0);
630 //==========================================================================
632 // ufoSetInFileNameReuse
634 //==========================================================================
635 UFO_FORCE_INLINE
void ufoSetInFileNameReuse (const char *fname
) {
636 ufoSetInFileNameEx(fname
, 1);
640 //==========================================================================
644 //==========================================================================
645 void ufoSetUserAbort (void) {
650 //==========================================================================
654 //==========================================================================
655 static UfoHandle
*ufoAllocHandle (uint32_t typeid) {
656 ufo_assert(typeid != UFO_HANDLE_FREE
);
657 UfoHandle
*newh
= ufoHandleFreeList
;
659 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
660 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
661 // due to offsets, this is the maximum number of handles we can have
662 if (newsz
> 0x1ffffU
) {
663 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
664 newsz
= 0x1ffffU
+ 1U;
665 ufo_assert(newsz
> ufoHandlesAlloted
);
667 UfoHandle
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
668 if (nh
== NULL
) ufoFatal("out of memory for handle table");
670 ufoHandlesAlloted
= newsz
;
672 newh
= calloc(1, sizeof(UfoHandle
));
673 if (newh
== NULL
) ufoFatal("out of memory for handle info");
674 ufoHandles
[ufoHandlesUsed
] = newh
;
675 // setup new handle info
676 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
679 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
680 ufoHandleFreeList
= newh
->next
;
682 // setup new handle info
683 newh
->typeid = typeid;
692 //==========================================================================
696 //==========================================================================
697 static void ufoFreeHandle (UfoHandle
*hh
) {
699 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
700 if (hh
->data
) free(hh
->data
);
701 hh
->typeid = UFO_HANDLE_FREE
;
705 hh
->next
= ufoHandleFreeList
;
706 ufoHandleFreeList
= hh
;
711 //==========================================================================
715 //==========================================================================
716 static UfoHandle
*ufoGetHandle (uint32_t hh
) {
718 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
719 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
720 if (hh
< ufoHandlesUsed
) {
721 res
= ufoHandles
[hh
];
722 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
733 //==========================================================================
737 //==========================================================================
738 static void setLastIncPath (const char *fname
, int system
) {
739 if (fname
== NULL
|| fname
[0] == 0) {
741 if (ufoLastSysIncPath
) free(ufoLastIncPath
);
742 ufoLastSysIncPath
= NULL
;
744 if (ufoLastIncPath
) free(ufoLastIncPath
);
745 ufoLastIncPath
= strdup(".");
751 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
752 ufoLastSysIncPath
= strdup(fname
);
753 lslash
= ufoLastSysIncPath
;
754 cpos
= ufoLastSysIncPath
;
756 if (ufoLastIncPath
) free(ufoLastIncPath
);
757 ufoLastIncPath
= strdup(fname
);
758 lslash
= ufoLastIncPath
;
759 cpos
= ufoLastIncPath
;
763 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
765 if (*cpos
== '/') lslash
= cpos
;
774 //==========================================================================
776 // ufoClearIncludePath
778 // required for UrAsm
780 //==========================================================================
781 void ufoClearIncludePath (void) {
782 if (ufoLastIncPath
!= NULL
) {
783 free(ufoLastIncPath
);
784 ufoLastIncPath
= NULL
;
786 if (ufoLastSysIncPath
!= NULL
) {
787 free(ufoLastSysIncPath
);
788 ufoLastSysIncPath
= NULL
;
793 //==========================================================================
797 //==========================================================================
798 static void ufoErrorPrintFile (FILE *fo
, const char *errwarn
) {
799 if (ufoInFileName
!= NULL
) {
800 fprintf(fo
, "UFO %s at file %s, line %d: ", errwarn
, ufoInFileName
, ufoInFileLine
);
802 fprintf(fo
, "UFO %s somewhere in time: ", errwarn
);
807 //==========================================================================
811 //==========================================================================
812 static void ufoErrorMsgV (const char *errwarn
, const char *fmt
, va_list ap
) {
814 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
815 ufoErrorPrintFile(stderr
, errwarn
);
816 vfprintf(stderr
, fmt
, ap
);
823 //==========================================================================
827 //==========================================================================
828 __attribute__((format(printf
, 1, 2)))
829 void ufoWarning (const char *fmt
, ...) {
832 ufoErrorMsgV("WARNING", fmt
, ap
);
836 //==========================================================================
840 //==========================================================================
841 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
842 void ufoFatal (const char *fmt
, ...) {
848 ufoErrorMsgV("ERROR", fmt
, ap
);
849 if (!ufoInBacktrace
) {
851 ufoBacktrace(ufoIP
, 1);
854 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
857 #ifdef UFO_DEBUG_FATAL_ABORT
868 // ////////////////////////////////////////////////////////////////////////// //
869 // working with the stacks
870 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
871 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); --ufoSP
; }
872 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
873 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
874 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
875 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
876 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
; }
877 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
; }
878 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
; }
880 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
881 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
882 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
); }
883 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
; }
885 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
886 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); --ufoRP
; }
887 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
888 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
889 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
891 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
894 //==========================================================================
898 //==========================================================================
899 static void ufoImgEnsureSize (uint32_t addr
) {
900 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
901 if (addr
>= ufoImageSize
) {
902 // 64MB should be enough for everyone!
903 if (addr
>= 0x04000000U
) {
904 ufoFatal("image grown too big (addr=0%08XH)", addr
);
906 const uint32_t osz
= ufoImageSize
;
908 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
909 ufo_assert(nsz
> addr
);
910 uint32_t *nimg
= realloc(ufoImage
, nsz
);
912 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
913 ufoImageSize
/ 1024u / 1024u,
914 nsz
/ 1024u / 1024u);
918 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
923 //==========================================================================
927 //==========================================================================
928 static void ufoImgEnsureTemp (uint32_t addr
) {
929 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
930 if (addr
>= ufoImageTempSize
) {
931 if (addr
>= 1024u * 1024u) {
932 ufoFatal("Forth segmentation fault at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
934 const uint32_t osz
= ufoImageTempSize
;
936 const uint32_t nsz
= (addr
|0x00001fffU
) + 1U;
937 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
939 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
940 ufoImageTempSize
/ 1024u,
944 ufoImageTempSize
= nsz
;
945 memset((char *)ufoImageTemp
+ osz
, 0, (nsz
- osz
));
950 #ifdef UFO_FAST_MEM_ACCESS
951 //==========================================================================
957 //==========================================================================
958 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
959 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
960 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
961 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
962 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
963 addr
&= UFO_ADDR_TEMP_MASK
;
964 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
965 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
967 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
972 //==========================================================================
978 //==========================================================================
979 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
980 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
981 if (addr
+ 1u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 1u);
982 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
983 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
984 addr
&= UFO_ADDR_TEMP_MASK
;
985 if (addr
+ 1u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 1u);
986 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
988 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
993 //==========================================================================
999 //==========================================================================
1000 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1001 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1002 if (addr
+ 3u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 3u);
1003 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
1004 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1005 addr
&= UFO_ADDR_TEMP_MASK
;
1006 if (addr
+ 3u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 3u);
1007 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
1009 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1014 //==========================================================================
1020 //==========================================================================
1021 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1022 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1023 if (addr
>= ufoImageSize
) {
1024 // accessing unallocated image area is segmentation fault
1025 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1027 return *((const uint8_t *)ufoImage
+ addr
);
1028 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1029 addr
&= UFO_ADDR_TEMP_MASK
;
1030 if (addr
>= ufoImageTempSize
) {
1031 // accessing unallocated image area is segmentation fault
1032 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1034 return *((const uint8_t *)ufoImageTemp
+ addr
);
1036 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1041 //==========================================================================
1047 //==========================================================================
1048 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1049 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1050 if (addr
+ 1u >= ufoImageSize
) {
1051 // accessing unallocated image area is segmentation fault
1052 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1054 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
1055 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1056 addr
&= UFO_ADDR_TEMP_MASK
;
1057 if (addr
+ 1u >= ufoImageTempSize
) {
1058 // accessing unallocated image area is segmentation fault
1059 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1061 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1063 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1068 //==========================================================================
1074 //==========================================================================
1075 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1076 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1077 if (addr
+ 3u >= ufoImageSize
) {
1078 // accessing unallocated image area is segmentation fault
1079 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1081 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
1082 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1083 addr
&= UFO_ADDR_TEMP_MASK
;
1084 if (addr
+ 3u >= ufoImageTempSize
) {
1085 // accessing unallocated image area is segmentation fault
1086 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1088 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1090 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1096 //==========================================================================
1102 //==========================================================================
1103 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1105 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1106 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
1107 imgptr
= &ufoImage
[addr
/4u];
1108 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1109 addr
&= UFO_ADDR_TEMP_MASK
;
1110 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
1111 imgptr
= &ufoImageTemp
[addr
/4u];
1113 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1115 const uint8_t val
= (uint8_t)value
;
1116 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1120 //==========================================================================
1126 //==========================================================================
1127 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1128 ufoImgPutU8(addr
, value
&0xffU
);
1129 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1133 //==========================================================================
1139 //==========================================================================
1140 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1141 ufoImgPutU16(addr
, value
&0xffffU
);
1142 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1146 //==========================================================================
1152 //==========================================================================
1153 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1155 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1156 if (addr
>= ufoImageSize
) return 0;
1157 imgptr
= &ufoImage
[addr
/4u];
1158 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1159 addr
&= UFO_ADDR_TEMP_MASK
;
1160 if (addr
>= ufoImageTempSize
) return 0;
1161 imgptr
= &ufoImageTemp
[addr
/4u];
1163 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1166 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1167 return (uint32_t)val
;
1171 //==========================================================================
1177 //==========================================================================
1178 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1179 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1183 //==========================================================================
1189 //==========================================================================
1190 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1191 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1196 //==========================================================================
1198 // ufoEnsureDebugSize
1200 //==========================================================================
1201 UFO_DISABLE_INLINE
void ufoEnsureDebugSize (uint32_t sdelta
) {
1202 ufo_assert(sdelta
!= 0);
1203 if (ufoDebugImageSize
!= 0) {
1204 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1205 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1206 // grow by 32KB, this should be more than enough
1207 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0x7fffU
) + 1u;
1208 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1209 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1210 ufoDebugImage
= ndb
;
1211 ufoDebugImageSize
= newsz
;
1214 // initial allocation: 32KB, quite a lot
1215 ufo_assert(ufoDebugImage
== NULL
);
1216 ufo_assert(ufoDebugImageUsed
== 0);
1217 ufoDebugImageSize
= 1024 * 32;
1218 ufoDebugImage
= malloc(ufoDebugImageSize
);
1219 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1224 #define UFO_DBG_PUT_U4(val_) do { \
1225 const uint32_t vv_ = (val_); \
1226 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1227 ufoDebugImageUsed += 4u; \
1234 ...first line info header...
1235 line info header (or reset):
1236 db 0 ; zero line delta
1237 dw followFileInfoSize ; either it, or 0 if reused
1238 dd fileInfoOfs ; present only if reused
1246 dd nameLen ; without terminating 0
1247 ...name... (0-terminated)
1249 we will never compare file names: length and hash should provide
1250 good enough unique identifier.
1252 static uint8_t *ufoDebugImage = NULL;
1253 static uint32_t ufoDebugImageUsed = 0; // in bytes
1254 static uint32_t ufoDebugImageSize = 0; // in bytes
1255 static uint32_t ufoDebugFileNameHash = 0; // current file name hash
1256 static uint32_t ufoDebugFileNameLen = 0; // current file name length
1257 static uint32_t ufoDebugCurrDP = 0;
1261 //==========================================================================
1263 // ufoSkipDebugVarInt
1265 //==========================================================================
1266 static __attribute__((unused
)) uint32_t ufoSkipDebugVarInt (uint32_t ofs
) {
1269 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1270 byte
= ufoDebugImage
[ofs
]; ofs
+= 1u;
1271 } while (byte
>= 0x80);
1276 //==========================================================================
1278 // ufoCalcDebugVarIntSize
1280 //==========================================================================
1281 UFO_FORCE_INLINE
uint8_t ufoCalcDebugVarIntSize (uint32_t v
) {
1291 //==========================================================================
1293 // ufoGetDebugVarInt
1295 //==========================================================================
1296 static __attribute__((unused
)) uint32_t ufoGetDebugVarInt (uint32_t ofs
) {
1301 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1302 byte
= ufoDebugImage
[ofs
];
1303 v
|= (uint32_t)(byte
& 0x7f) << shift
;
1308 } while (byte
>= 0x80);
1313 //==========================================================================
1315 // ufoPutDebugVarInt
1317 //==========================================================================
1318 UFO_FORCE_INLINE
void ufoPutDebugVarInt (uint32_t v
) {
1319 ufoEnsureDebugSize(5u); // maximum size
1322 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)(v
| 0x80u
);
1324 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)v
;
1326 ufoDebugImageUsed
+= 1;
1332 #ifdef UFO_DEBUG_DEBUG
1333 //==========================================================================
1337 //==========================================================================
1338 static void ufoDumpDebugImage (void) {
1340 uint32_t dbgpos
= 4u; // first line header info
1341 uint32_t lastline
= 0;
1342 uint32_t lastdp
= 0;
1343 while (dbgpos
< ufoDebugImageUsed
) {
1344 if (ufoDebugImage
[dbgpos
] == 0) {
1346 dbgpos
+= 1u; // skip flag
1347 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1348 lastdp
= ufoGetDebugVarInt(dbgpos
);
1349 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1350 if (fhdrSize
== 0) {
1352 const uint32_t infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1353 fprintf(stderr
, "*** OLD FILE: %s\n", (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u));
1354 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2]);
1355 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1]);
1358 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
+ 3u * 4u));
1359 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[2]);
1360 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[1]);
1363 fprintf(stderr
, "LINES-OFS: 0x%08x (hsz: %u -- 0x%08x)\n", dbgpos
, fhdrSize
, fhdrSize
);
1364 lastline
= ~(uint32_t)0;
1366 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1367 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1368 ufo_assert(ln
!= 0);
1370 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1371 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1373 fprintf(stderr
, " line %6u: edp=%u\n", lastline
, lastdp
);
1381 //==========================================================================
1383 // ufoRecordDebugCheckFile
1385 // if we moved to the new file:
1386 // put "line info header"
1387 // put new file info (or reuse old)
1389 //==========================================================================
1390 UFO_FORCE_INLINE
void ufoRecordDebugCheckFile (void) {
1391 if (ufoDebugImageUsed
== 0 ||
1392 ufoDebugFileNameLen
!= ufoInFileNameLen
||
1393 ufoDebugFileNameHash
!= ufoInFileNameHash
)
1395 // new file record (or reuse old one)
1396 const int initial
= (ufoDebugImageUsed
== 0);
1397 uint32_t fileRec
= 0;
1398 // try to find and old one
1400 fileRec
= *(const uint32_t *)ufoDebugImage
;
1402 fprintf(stderr
, "*** NEW-FILE(%u): 0x%08x: <%s> (frec=0x%08x)\n", ufoInFileNameLen
,
1403 ufoInFileNameHash
, ufoInFileName
, fileRec
);
1405 while (fileRec
!= 0 &&
1406 (ufoInFileNameLen
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1] ||
1407 ufoInFileNameHash
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]))
1410 fprintf(stderr
, "*** FRCHECK: 0x%08x\n", fileRec
);
1411 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1412 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1413 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1414 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1416 fileRec
= *(const uint32_t *)(ufoDebugImage
+ fileRec
);
1419 fprintf(stderr
, "*** FRCHECK-DONE: 0x%08x\n", fileRec
);
1421 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1422 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1423 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1424 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1428 ufoEnsureDebugSize(8u);
1429 *(uint32_t *)ufoDebugImage
= 0;
1431 // write "line info header"
1433 ufoEnsureDebugSize(32u);
1434 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1435 // file record size: 0 (reused)
1436 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = 0; ufoDebugImageUsed
+= 2u;
1438 ufoPutDebugVarInt(ufoDebugCurrDP
);
1440 UFO_DBG_PUT_U4(fileRec
);
1442 // name, trailing 0 byte, 3 dword fields
1443 const uint32_t finfoSize
= ufoInFileNameLen
+ 1u + 3u * 4u;
1444 ufo_assert(finfoSize
< 65536u);
1445 ufoEnsureDebugSize(finfoSize
+ 32u);
1447 *(uint32_t *)ufoDebugImage
= 0;
1448 ufoDebugImageUsed
= 4;
1450 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1452 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = (uint16_t)finfoSize
; ufoDebugImageUsed
+= 2u;
1454 ufoPutDebugVarInt(ufoDebugCurrDP
);
1455 // file record follows
1456 // fix file info offsets
1457 uint32_t lastOfs
= *(const uint32_t *)ufoDebugImage
;
1458 *(uint32_t *)ufoDebugImage
= ufoDebugImageUsed
;
1459 UFO_DBG_PUT_U4(lastOfs
);
1460 // save file info hash
1461 UFO_DBG_PUT_U4(ufoInFileNameHash
);
1462 // save file info length
1463 UFO_DBG_PUT_U4(ufoInFileNameLen
);
1465 if (ufoInFileNameLen
!= 0) {
1466 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, ufoInFileNameLen
+ 1u);
1467 ufoDebugImageUsed
+= ufoInFileNameLen
+ 1u;
1469 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u;
1472 ufoDebugFileNameLen
= ufoInFileNameLen
;
1473 ufoDebugFileNameHash
= ufoInFileNameHash
;
1474 ufoDebugLastLine
= ~(uint32_t)0;
1475 ufoDebugLastLinePCOfs
= 0;
1476 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1481 //==========================================================================
1483 // ufoRecordDebugRecordLine
1485 //==========================================================================
1486 UFO_FORCE_INLINE
void ufoRecordDebugRecordLine (uint32_t line
, uint32_t newhere
) {
1487 if (line
== ufoDebugLastLine
) {
1488 ufo_assert(ufoDebugLastLinePCOfs
!= 0);
1489 ufoDebugImageUsed
= ufoDebugLastLinePCOfs
;
1492 fprintf(stderr
, "FL-NEW-LINE(0x%08x): <%s>; new line: %u (old: %u)\n",
1494 ufoInFileName
, line
, ufoDebugLastLine
);
1496 ufoPutDebugVarInt(line
- ufoDebugLastLine
);
1497 ufoDebugLastLinePCOfs
= ufoDebugImageUsed
;
1498 ufoDebugLastLine
= line
;
1499 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1501 ufoPutDebugVarInt(newhere
- ufoDebugLastLineDP
);
1502 ufoDebugCurrDP
= newhere
;
1506 //==========================================================================
1510 //==========================================================================
1511 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1512 if (newhere
> ufoDebugCurrDP
) {
1513 uint32_t ln
= (uint32_t)ufoInFileLine
;
1514 if (ln
== ~(uint32_t)0) ln
= 0;
1516 fprintf(stderr
, "FL: <%s>; line: %d\n", ufoInFileName
, ufoInFileLine
);
1518 ufoRecordDebugCheckFile();
1519 ufoRecordDebugRecordLine(ln
, newhere
);
1524 //==========================================================================
1526 // ufoGetWordEndAddrYFA
1528 //==========================================================================
1529 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1531 const uint32_t oyfa
= yfa
;
1532 yfa
= ufoImgGetU32(yfa
);
1534 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1536 if ((yfa
& UFO_ADDR_TEMP_BIT
) != 0) {
1537 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1540 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1543 yfa
= UFO_YFA_TO_WST(yfa
);
1552 //==========================================================================
1554 // ufoGetWordEndAddr
1556 //==========================================================================
1557 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1559 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa
)));
1566 //==========================================================================
1572 // WARNING: this is SLOW!
1574 //==========================================================================
1575 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1578 //fprintf(stderr, "ufoFindWordForIP:000: ip=0x%08x\n", ip);
1579 // iterate over all words
1580 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1581 //fprintf(stderr, "ufoFindWordForIP:001: xfa=0x%08x\n", xfa);
1583 while (res
== 0 && xfa
!= 0) {
1584 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1585 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1586 //fprintf(stderr, "ufoFindWordForIP:002: yfa=0x%08x; wst=0x%08x\n", yfa, wst);
1587 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1588 if (ip
>= wst
&& ip
< wend
) {
1589 res
= UFO_YFA_TO_NFA(yfa
);
1591 xfa
= ufoImgGetU32(xfa
);
1600 //==========================================================================
1604 // return file name or `NULL`
1606 // WARNING: this is SLOW!
1608 //==========================================================================
1609 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
,
1610 uint32_t *nlen
, uint32_t *nhash
)
1612 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1613 const char *filename
= NULL
;
1614 uint32_t dbgpos
= 4u; // first line header info
1615 uint32_t lastline
= 0;
1616 uint32_t lastdp
= 0;
1617 uint32_t namelen
= 0;
1618 uint32_t namehash
= 0;
1619 while (dbgpos
< ufoDebugImageUsed
) {
1620 if (ufoDebugImage
[dbgpos
] == 0) {
1622 dbgpos
+= 1u; // skip flag
1623 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1624 lastdp
= ufoGetDebugVarInt(dbgpos
);
1625 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1627 if (fhdrSize
== 0) {
1629 infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1634 filename
= (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u);
1635 namelen
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2];
1636 namehash
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1];
1637 if (filename
[0] == 0) filename
= NULL
;
1639 lastline
= ~(uint32_t)0;
1641 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1642 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1643 ufo_assert(ln
!= 0);
1645 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1646 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1647 if (ip
>= lastdp
&& ip
< lastdp
+ edp
) {
1648 if (line
) *line
= lastline
;
1649 if (nlen
) *nlen
= namelen
;
1650 if (nhash
) *nhash
= namehash
;
1657 if (line
) *line
= 0;
1658 if (nlen
) *nlen
= 0;
1659 if (nhash
) *nlen
= 0;
1664 //==========================================================================
1668 //==========================================================================
1669 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1670 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
1672 dp
= ufoImgGetU32(ufoAddrDP
);
1673 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1675 ufoImgPutU32(ufoAddrDP
, dp
);
1677 dp
= ufoImgGetU32(ufoAddrDPTemp
);
1678 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1680 ufoImgPutU32(ufoAddrDPTemp
, dp
);
1685 //==========================================================================
1689 //==========================================================================
1690 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1691 ufoImgPutU8(UFO_GET_DP(), value
);
1696 //==========================================================================
1700 //==========================================================================
1701 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1702 ufoImgPutU32(UFO_GET_DP(), value
);
1707 #ifdef UFO_FAST_MEM_ACCESS
1709 //==========================================================================
1711 // ufoImgEmitU32_NoInline
1715 //==========================================================================
1716 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1717 ufoImgPutU32(UFO_GET_DP(), value
);
1723 //==========================================================================
1725 // ufoImgEmitU32_NoInline
1729 //==========================================================================
1730 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1731 ufoImgPutU32(UFO_GET_DP(), value
);
1738 //==========================================================================
1742 // this understands handle addresses
1744 //==========================================================================
1745 UFO_FORCE_INLINE
uint32_t ufoImgGetU8Ext (uint32_t addr
) {
1746 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1747 return ufoImgGetU8(addr
);
1751 UFCALL(PAR_HANDLE_LOAD_BYTE
);
1757 //==========================================================================
1761 // this understands handle addresses
1763 //==========================================================================
1764 UFO_FORCE_INLINE
void ufoImgPutU8Ext (uint32_t addr
, uint32_t value
) {
1765 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1766 ufoImgPutU8(addr
, value
);
1771 UFCALL(PAR_HANDLE_STORE_BYTE
);
1776 //==========================================================================
1780 //==========================================================================
1781 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
1782 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1786 //==========================================================================
1790 //==========================================================================
1791 UFO_FORCE_INLINE
void ufoResetTib (void) {
1792 uint32_t defTIB
= ufoImgGetU32(ufoAddrDefTIB
);
1793 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1795 // create new TIB handle
1796 UfoHandle
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
1797 defTIB
= tibh
->ufoHandle
;
1798 ufoImgPutU32(ufoAddrDefTIB
, defTIB
);
1800 if ((defTIB
& UFO_ADDR_HANDLE_BIT
) != 0) {
1801 UfoHandle
*hh
= ufoGetHandle(defTIB
);
1802 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
1803 if (hh
->size
== 0) {
1804 ufo_assert(hh
->data
== NULL
);
1805 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
1806 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
1807 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
1810 const uint32_t oldA
= ufoRegA
;
1811 ufoImgPutU32(ufoAddrTIBx
, defTIB
);
1812 ufoImgPutU32(ufoAddrINx
, 0);
1814 ufoPush(0); // value
1815 ufoPush(0); // offset
1816 UFCALL(CPOKE_REGA_IDX
);
1821 //==========================================================================
1825 //==========================================================================
1826 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
1827 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1828 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1829 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1830 if ((tib
& UFO_ADDR_HANDLE_BIT
) != 0) {
1831 UfoHandle
*hh
= ufoGetHandle(tib
);
1833 ufoFatal("cannot resize TIB, TIB is not a handle");
1835 if (hh
->size
< size
) {
1836 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
1837 uint8_t *nx
= realloc(hh
->data
, newsz
);
1838 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
1845 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib
);
1851 //==========================================================================
1855 //==========================================================================
1857 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1858 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1859 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1860 ufoFatal("cannot query TIB, TIB is not a handle");
1862 UfoHandle *hh = ufoGetHandle(tib);
1864 ufoFatal("cannot query TIB, TIB is not a handle");
1871 //==========================================================================
1875 //==========================================================================
1876 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
1877 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
1881 //==========================================================================
1885 //==========================================================================
1886 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
1887 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1888 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1889 return (uint8_t)ufoImgGetU8Ext(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
1896 //==========================================================================
1900 //==========================================================================
1901 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
1902 const uint32_t oldA
= ufoRegA
;
1903 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
1905 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
1906 UFCALL(CPOKE_REGA_IDX
);
1911 //==========================================================================
1915 //==========================================================================
1916 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
1917 const uint8_t ch
= ufoTibPeekCh();
1918 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
1923 //==========================================================================
1927 //==========================================================================
1928 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
1929 (void)ufoTibGetCh();
1933 // ////////////////////////////////////////////////////////////////////////// //
1934 // native CFA implementations
1937 //==========================================================================
1941 //==========================================================================
1942 static void ufoDoForth (uint32_t pfa
) {
1948 //==========================================================================
1952 //==========================================================================
1953 static void ufoDoVariable (uint32_t pfa
) {
1958 //==========================================================================
1960 // ufoDoUserVariable
1962 //==========================================================================
1963 static void ufoDoUserVariable (uint32_t pfa
) {
1964 ufoPush(ufoImgGetU32(pfa
));
1968 //==========================================================================
1972 //==========================================================================
1973 static void ufoDoValue (uint32_t pfa
) {
1974 ufoPush(ufoImgGetU32(pfa
));
1978 //==========================================================================
1982 //==========================================================================
1983 static void ufoDoConst (uint32_t pfa
) {
1984 ufoPush(ufoImgGetU32(pfa
));
1988 //==========================================================================
1992 //==========================================================================
1993 static void ufoDoDefer (uint32_t pfa
) {
1994 const uint32_t cfa
= ufoImgGetU32(pfa
);
2002 //==========================================================================
2006 //==========================================================================
2007 static void ufoDoVoc (uint32_t pfa
) {
2008 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
2012 //==========================================================================
2016 //==========================================================================
2017 static void ufoDoCreate (uint32_t pfa
) {
2022 //==========================================================================
2026 // this also increments last used file id
2028 //==========================================================================
2029 static void ufoPushInFile (void) {
2030 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
2031 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2032 stk
->fl
= ufoInFile
;
2033 stk
->fname
= ufoInFileName
;
2034 stk
->fline
= ufoInFileLine
;
2035 stk
->id
= ufoFileId
;
2036 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
2037 stk
->sysincpath
= (ufoLastSysIncPath
? strdup(ufoLastSysIncPath
) : NULL
);
2038 ufoFileStackPos
+= 1;
2040 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
2042 ufoLastUsedFileId
+= 1;
2043 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
2044 //ufoLastIncPath = NULL;
2048 //==========================================================================
2050 // ufoWipeIncludeStack
2052 //==========================================================================
2053 static void ufoWipeIncludeStack (void) {
2054 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2055 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2056 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2057 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2058 while (ufoFileStackPos
!= 0) {
2059 ufoFileStackPos
-= 1;
2060 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2061 if (stk
->fl
) fclose(stk
->fl
);
2062 if (stk
->fname
) free(stk
->fname
);
2063 if (stk
->incpath
) free(stk
->incpath
);
2068 //==========================================================================
2072 //==========================================================================
2073 static void ufoPopInFile (void) {
2074 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
2075 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2076 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2077 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2078 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2079 ufoFileStackPos
-= 1;
2080 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2081 ufoInFile
= stk
->fl
;
2082 ufoSetInFileNameReuse(stk
->fname
);
2083 ufoInFileLine
= stk
->fline
;
2084 ufoLastIncPath
= stk
->incpath
;
2085 ufoLastSysIncPath
= stk
->sysincpath
;
2086 ufoFileId
= stk
->id
;
2088 #ifdef UFO_DEBUG_INCLUDE
2089 if (ufoInFileName
== NULL
) {
2090 fprintf(stderr
, "INC-POP: no more files.\n");
2092 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
2098 //==========================================================================
2102 //==========================================================================
2103 void ufoDeinit (void) {
2104 #ifdef UFO_DEBUG_WRITE_MAIN_IMAGE
2106 FILE *fo
= fopen("zufo_main.img", "w");
2107 uint32_t dpTemp
= ufoImgGetU32(ufoAddrDPTemp
);
2108 uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2109 if ((dpMain
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) dpMain
= ufoImageSize
;
2110 if (dpTemp
!= 0 && (dpTemp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
2111 if (dpTemp
> dpMain
) dpMain
= dpTemp
;
2113 fwrite(ufoImage
, dpMain
, 1, fo
);
2118 #ifdef UFO_DEBUG_WRITE_DEBUG_IMAGE
2120 FILE *fo
= fopen("zufo_debug.img", "w");
2121 fwrite(ufoDebugImage
, ufoDebugImageUsed
, 1, fo
);
2126 #ifdef UFO_DEBUG_DEBUG
2128 uint32_t dpTemp
= ufoImgGetU32(ufoAddrDPTemp
);
2129 uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2130 if ((dpMain
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) dpMain
= ufoImageSize
;
2131 if (dpTemp
!= 0 && (dpTemp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
2132 if (dpTemp
> dpMain
) dpMain
= dpTemp
;
2134 fprintf(stderr
, "UFO: image used: %u; size: %u\n",
2135 dpMain
, ufoImageSize
);
2136 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n",
2137 ufoDebugImageUsed
, ufoDebugImageSize
);
2138 ufoDumpDebugImage();
2143 ufoCurrState
= NULL
;
2144 ufoYieldedState
= NULL
;
2145 ufoDebuggerState
= NULL
;
2146 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
2147 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
2149 uint32_t stid
= fidx
* 32u;
2151 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
2152 stid
+= 1u; bmp
>>= 1;
2157 free(ufoDebugImage
);
2158 ufoDebugImage
= NULL
;
2159 ufoDebugImageUsed
= 0;
2160 ufoDebugImageSize
= 0;
2161 ufoDebugFileNameHash
= 0;
2162 ufoDebugFileNameLen
= 0;
2163 ufoDebugLastLine
= 0;
2164 ufoDebugLastLinePCOfs
= 0;
2165 ufoDebugLastLineDP
= 0;
2169 ufoClearCondDefines();
2170 ufoWipeIncludeStack();
2172 // release all includes
2174 if (ufoInFileName
) free(ufoInFileName
);
2175 if (ufoLastIncPath
) free(ufoLastIncPath
);
2176 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
2177 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
2178 ufoInFileNameHash
= 0; ufoInFileNameLen
= 0;
2182 ufoForthCFAs
= NULL
;
2189 ufoMode
= UFO_MODE_NATIVE
;
2190 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
2194 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
2195 UfoHandle
*hh
= ufoHandles
[f
];
2197 if (hh
->data
!= NULL
) free(hh
->data
);
2201 if (ufoHandles
!= NULL
) free(ufoHandles
);
2202 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
2203 ufoHandleFreeList
= NULL
;
2205 ufoLastEmitWasCR
= 1;
2207 ufoClearCondDefines();
2211 //==========================================================================
2213 // ufoDumpWordHeader
2215 //==========================================================================
2216 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
2217 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
2219 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
2220 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
2221 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
2222 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
2223 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
2224 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
2225 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
2226 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
2227 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
2228 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
2229 const uint32_t nlen
= ufoImgGetU8(nfa
);
2230 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
2231 const uint32_t flags
= ufoImgGetU32(nfa
);
2232 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
2233 if ((flags
& 0xffff0000U
) != 0) {
2234 fprintf(stderr
, " FLAGS:");
2235 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
2236 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
2237 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
2238 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
2239 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
2240 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
2241 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
2242 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
2243 fputc('\n', stderr
);
2245 if ((flags
& 0xff00U
) != 0) {
2246 fprintf(stderr
, " ARGS: ");
2247 switch (flags
& UFW_WARG_MASK
) {
2248 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
2249 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
2250 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
2251 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
2252 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
2253 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
2254 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
2255 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
2256 case UFW_WARG_DATASKIP
: fprintf(stderr
, "DATA"); break;
2257 default: fprintf(stderr
, "wtf?!"); break;
2259 fputc('\n', stderr
);
2261 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
2262 fprintf(stderr
, " NAME(%u): ", nlen
);
2263 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2264 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2265 if (ch
<= 32 || ch
>= 127) {
2266 fprintf(stderr
, "\\x%02x", ch
);
2268 fprintf(stderr
, "%c", (char)ch
);
2271 fprintf(stderr
, "\n");
2272 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
2277 //==========================================================================
2283 //==========================================================================
2284 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
2288 #ifdef UFO_DEBUG_FIND_WORD
2289 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
2290 (unsigned) wnlen
, (const char *)wname
,
2291 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
2292 ufoDumpWordHeader(lfa
);
2294 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
2295 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
2296 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
2297 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
2299 const uint32_t nlen
= lenflags
&0xffU
;
2300 if (nlen
== wnlen
) {
2301 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
2303 while (pos
< nlen
) {
2304 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
2305 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
2306 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
2307 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
2308 if (c0
!= c1
) break;
2314 res
= UFO_ALIGN4(naddr
);
2323 //==========================================================================
2329 //==========================================================================
2330 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2331 uint32_t vocid
, int allowvochid
)
2334 if (wname
== NULL
) ufo_assert(wnlen
== 0);
2335 if (wnlen
!= 0 && vocid
!= 0) {
2336 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2337 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2338 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
2339 (unsigned) wnlen
, (const char *)wname
,
2340 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
2342 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
2343 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
2344 // hash table present, use it
2345 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2346 bfa
= ufoImgGetU32(bfa
);
2347 while (res
== 0 && bfa
!= 0) {
2348 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2349 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
2351 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
2352 bfa
= ufoImgGetU32(bfa
);
2355 // no hash table, use linear search
2356 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
2357 lfa
= ufoImgGetU32(lfa
);
2358 while (res
== 0 && lfa
!= 0) {
2359 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
2360 lfa
= ufoImgGetU32(lfa
);
2368 //==========================================================================
2372 // return part after the colon, or `NULL`
2374 //==========================================================================
2375 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
2376 const void *res
= NULL
;
2378 ufo_assert(wname
!= NULL
);
2379 const char *str
= (const char *)wname
;
2380 while (wnlen
!= 0 && str
[0] != ':') {
2381 str
+= 1; wnlen
-= 1;
2384 res
= (const void *)(str
+ 1); // skip colon
2391 //==========================================================================
2393 // ufoFindWordInVocAndParents
2395 //==========================================================================
2396 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2397 uint32_t vocid
, int allowvochid
)
2400 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2401 while (res
== 0 && vocid
!= 0) {
2402 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2403 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2409 //==========================================================================
2411 // ufoFindWordNameRes
2413 // find with name resolution
2417 //==========================================================================
2418 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2420 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2421 ufo_assert(wname
!= NULL
);
2423 const void *stx
= wname
;
2424 wname
= ufoFindColon(wname
, wnlen
);
2425 if (wname
!= NULL
) {
2426 // look in all vocabs (excluding hidden ones)
2427 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2428 ufo_assert(xlen
> 0 && xlen
< 255);
2429 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2430 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2431 #ifdef UFO_DEBUG_FIND_WORD_COLON
2432 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2433 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2435 while (res
== 0 && voclink
!= 0) {
2436 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2437 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2439 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2441 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2444 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2445 ufo_assert(voclink
!= 0);
2447 #ifdef UFO_DEBUG_FIND_WORD_COLON
2448 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2449 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2451 while (res
!= 0 && wname
!= NULL
) {
2452 // first, the whole rest
2453 res
= ufoFindWordInVocAndParents(wname
, wnlen
, 0, vocid
, 1);
2458 wname
= ufoFindColon(wname
, wnlen
);
2459 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2460 ufo_assert(xlen
> 0 && xlen
< 255);
2461 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2464 if (wname
!= NULL
) {
2465 // it should be a vocabulary
2466 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2467 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2468 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2484 //==========================================================================
2488 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2492 //==========================================================================
2493 static uint32_t ufoFindWord (const char *wname
) {
2495 if (wname
&& wname
[0] != 0) {
2496 const size_t wnlen
= strlen(wname
);
2497 ufo_assert(wnlen
< 8192);
2498 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2499 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2501 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2503 // first search in context
2504 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2506 // now try vocabulary stack
2507 uint32_t vstp
= ufoVSP
;
2508 while (res
== 0 && vstp
!= 0) {
2510 ctx
= ufoVocStack
[vstp
];
2511 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2514 // if not found, try name resolution
2515 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2522 //==========================================================================
2524 // ufoCreateWordHeader
2526 // create word header up to CFA, link to the current dictionary
2528 //==========================================================================
2529 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2530 if (wname
== NULL
) wname
= "";
2531 const size_t wnlen
= strlen(wname
);
2532 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2533 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2534 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2535 ufo_assert(curr
!= 0);
2537 const uint32_t warn
= ufoImgGetU32(ufoAddrRedefineWarning
);
2538 if (wnlen
!= 0 && warn
!= UFO_REDEF_WARN_DONT_CARE
) {
2540 if (warn
!= UFO_REDEF_WARN_PARENTS
) {
2541 cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2543 cfa
= ufoFindWordInVocAndParents(wname
, wnlen
, hash
, curr
, 1);
2546 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2547 const uint32_t flags
= ufoImgGetU32(nfa
);
2548 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2549 ufoFatal("trying to redefine protected word '%s'", wname
);
2550 } else if (warn
!= UFO_REDEF_WARN_NONE
) {
2551 ufoWarning("redefining word '%s'", wname
);
2555 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2556 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2557 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2559 const uint32_t xfaAddr
= UFO_GET_DP();
2560 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2561 // link previous yfa here
2562 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2563 // fix YFA of the previous word
2565 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2567 // our XFA points to the previous XFA
2568 ufoImgEmitU32(lastxfa
); // xfa
2570 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2572 ufoImgEmitU32(0); // xfa
2574 ufoImgEmitU32(0); // yfa
2575 // bucket link (bfa)
2576 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2579 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2580 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2581 wname
, curr
, htbl
, bkt
);
2582 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2584 // bfa points to bfa
2585 const uint32_t bfa
= UFO_GET_DP();
2586 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2587 ufoImgPutU32(htbl
+ bkt
, bfa
);
2590 const uint32_t lfa
= UFO_GET_DP();
2591 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2593 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2595 ufoImgEmitU32(hash
);
2597 const uint32_t nfa
= UFO_GET_DP();
2598 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2599 const uint32_t nstart
= UFO_GET_DP();
2601 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2602 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2604 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2605 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2606 // name length, again
2607 ufo_assert(nend
- nstart
<= 255);
2608 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2609 ufo_assert((UFO_GET_DP() & 3) == 0);
2610 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2611 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2612 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2613 fprintf(stderr
, "*** NEW HEADER ***\n");
2614 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2615 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2616 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2617 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2618 ufoDumpWordHeader(lfa
);
2621 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2626 //==========================================================================
2630 //==========================================================================
2631 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2634 while (addr
< eaddr
) {
2635 uint32_t cfa
= ufoImgGetU32(addr
);
2636 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2637 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2638 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2639 uint32_t flags
= ufoImgGetU32(nfa
);
2640 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2641 uint32_t nlen
= flags
& 0xffU
;
2642 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2643 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2644 if (ch
<= 32 || ch
>= 127) {
2645 fprintf(fo
, "\\x%02x", ch
);
2647 fprintf(fo
, "%c", (char)ch
);
2651 switch (flags
& UFW_WARG_MASK
) {
2654 case UFW_WARG_BRANCH
:
2655 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2658 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2659 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2661 case UFW_WARG_C4STRZ
:
2662 count
= ufoImgGetU32(addr
); addr
+= 4;
2664 fprintf(fo
, " str:");
2665 for (int f
= 0; f
< count
; f
+= 1) {
2666 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2667 if (ch
<= 32 || ch
>= 127) {
2668 fprintf(fo
, "\\x%02x", ch
);
2670 fprintf(fo
, "%c", (char)ch
);
2673 addr
+= 1u; // skip zero byte
2674 addr
= UFO_ALIGN4(addr
);
2677 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2678 fprintf(fo
, " CFA:%u: ", cfa
);
2679 nfa
= UFO_CFA_TO_NFA(cfa
);
2680 nlen
= ufoImgGetU8(nfa
);
2681 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2682 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2683 if (ch
<= 32 || ch
>= 127) {
2684 fprintf(fo
, "\\x%02x", ch
);
2686 fprintf(fo
, "%c", (char)ch
);
2690 case UFW_WARG_CBLOCK
:
2691 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2693 case UFW_WARG_VOCID
:
2694 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2696 case UFW_WARG_C1STRZ
:
2697 count
= ufoImgGetU8(addr
); addr
+= 1;
2699 case UFW_WARG_DATASKIP
:
2700 fprintf(fo
, " DATA:%u", ufoImgGetU32(addr
));
2701 addr
+= ufoImgGetU32(addr
) + 4u;
2704 fprintf(fo
, " -- WTF?!\n");
2712 //==========================================================================
2716 //==========================================================================
2717 static void ufoDecompileWord (const uint32_t cfa
) {
2719 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
2720 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
2721 ufoDumpWordHeader(lfa
);
2722 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
2723 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
2724 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
2725 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
2726 fprintf(stdout
, "=======================\n");
2732 //==========================================================================
2734 // ufoBTShowWordName
2736 //==========================================================================
2737 static void ufoBTShowWordName (uint32_t nfa
) {
2739 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
2740 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2742 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
2743 if (ch
<= 32 || ch
>= 127) {
2744 fprintf(stderr
, "\\x%02x", ch
);
2746 fprintf(stderr
, "%c", (char)ch
);
2753 //==========================================================================
2757 //==========================================================================
2758 static void ufoBacktrace (uint32_t ip
, int showDataStack
) {
2759 // dump data stack (top 16)
2761 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2763 if (showDataStack
) {
2764 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
2765 uint32_t xsp
= ufoSP
;
2766 if (xsp
> 16) xsp
= 16;
2767 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2768 fprintf(stderr
, " %2u: 0x%08x %d%s\n",
2769 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
2770 (sp
== 0 ? " -- TOS" : ""));
2772 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
2775 // dump return stack (top 32)
2780 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
2782 nfa
= ufoFindWordForIP(ip
);
2784 fprintf(stderr
, " **: %8u -- ", ip
);
2785 ufoBTShowWordName(nfa
);
2786 fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
2787 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2788 fputc('\n', stderr
);
2791 uint32_t rp
= ufoRP
;
2792 uint32_t rscount
= 0;
2793 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
2794 while (rscount
!= 32 && rp
!= 0) {
2796 const uint32_t val
= ufoRStack
[rp
];
2797 nfa
= ufoFindWordForIP(val
- 4u);
2799 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
2800 ufoBTShowWordName(nfa
);
2801 fname
= ufoFindFileForIP(val
- 4u, &fline
, NULL
, NULL
);
2802 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2803 fputc('\n', stderr
);
2805 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
2809 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
2815 //==========================================================================
2819 //==========================================================================
2821 static void ufoDumpVocab (uint32_t vocid) {
2823 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2824 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2825 vochdr = ufoImgGetU32(vochdr);
2827 fprintf(stderr, "--- HEADER ---\n");
2828 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2829 fprintf(stderr, "========\n");
2830 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2831 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2832 fprintf(stderr, "--- HASH TABLE ---\n");
2833 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2834 uint32_t bfa = ufoImgGetU32(htbl);
2836 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2838 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2839 bfa = ufoImgGetU32(bfa);
2851 // if set, this will be used when we are out of include files. intended for UrAsm.
2852 // return 0 if there is no more lines, otherwise the string should be copied
2853 // to buffer, `*fname` and `*fline` should be properly set.
2854 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
2857 //==========================================================================
2859 // ufoLoadNextUserLine
2861 //==========================================================================
2862 static int ufoLoadNextUserLine (void) {
2863 uint32_t tibPos
= 0;
2864 const char *fname
= NULL
;
2867 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
2868 ufoCurrFileLine
[510] = 0;
2869 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2870 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
2873 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2874 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2876 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2877 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2878 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2880 ufoTibPokeChOfs(0, tibPos
+ slen
);
2882 if (fname
== NULL
) fname
= "<user>";
2883 ufoSetInFileName(fname
);
2884 ufoInFileLine
= fline
;
2892 //==========================================================================
2894 // ufoLoadNextLine_NativeMode
2896 // load next file line into TIB
2897 // always strips final '\n'
2899 // return 0 on EOF, 1 on success
2901 //==========================================================================
2902 static int ufoLoadNextLine (int crossInclude
) {
2904 uint32_t tibPos
= 0;
2907 if (ufoMode
== UFO_MODE_MACRO
) {
2908 //fprintf(stderr, "***MAC!\n");
2912 while (ufoInFile
!= NULL
&& !done
) {
2913 ufoCurrIncludeLineFileOfs
= ftell(ufoInFile
);
2914 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
2915 // check for a newline
2916 // if there is no newline char at the end, the string was truncated
2917 ufoCurrFileLine
[510] = 0;
2918 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2919 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2920 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2922 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2923 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2924 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2926 ufoTibPokeChOfs(0, tibPos
+ slen
);
2928 if (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
2932 // continuation, nothing to do
2935 // if we read nothing, this is EOF
2936 if (tibPos
== 0 && crossInclude
) {
2937 // we read nothing, and allowed to cross include boundaries
2946 // eof, try user-supplied input
2947 if (ufoFileStackPos
== 0) {
2948 return ufoLoadNextUserLine();
2953 // if we read at least something, this is not EOF
2959 // ////////////////////////////////////////////////////////////////////////// //
2964 UFWORD(DUMP_STACK
) {
2965 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2966 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
2967 uint32_t xsp
= ufoSP
;
2968 if (xsp
> 16) xsp
= 16;
2969 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2970 printf(" %2u: 0x%08x %d%s\n",
2971 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
2972 (sp
== 0 ? " -- TOS" : ""));
2974 if (ufoSP
> 16) printf(" ...more...\n");
2975 ufoLastEmitWasCR
= 1;
2980 UFWORD(UFO_BACKTRACE
) {
2982 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2983 if (ufoInFile
!= NULL
) {
2984 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
2986 fprintf(stderr
, "*** somewhere in time ***\n");
2988 ufoBacktrace(ufoIP
, 1);
2993 UFWORD(DUMP_STACK_TASK
) {
2994 UfoState
*st
= ufoFindState(ufoPop());
2995 if (st
== NULL
) ufoFatal("invalid state id");
2996 // temporarily switch the task
2997 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
2999 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3000 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
3001 uint32_t xsp
= ufoSP
;
3002 if (xsp
> 16) xsp
= 16;
3003 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
3004 printf(" %2u: 0x%08x %d%s\n",
3005 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
3006 (sp
== 0 ? " -- TOS" : ""));
3008 if (ufoSP
> 16) printf(" ...more...\n");
3009 ufoLastEmitWasCR
= 1;
3011 ufoCurrState
= oldst
;
3016 UFWORD(DUMP_RSTACK_TASK
) {
3017 UfoState
*st
= ufoFindState(ufoPop());
3018 if (st
== NULL
) ufoFatal("invalid state id");
3019 // temporarily switch the task
3020 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3023 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3024 if (ufoInFile
!= NULL
) {
3025 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3027 fprintf(stderr
, "*** somewhere in time ***\n");
3029 ufoBacktrace(ufoIP
, 0);
3031 ufoCurrState
= oldst
;
3036 UFWORD(UFO_BACKTRACE_TASK
) {
3037 UfoState
*st
= ufoFindState(ufoPop());
3038 if (st
== NULL
) ufoFatal("invalid state id");
3039 // temporarily switch the task
3040 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3043 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3044 if (ufoInFile
!= NULL
) {
3045 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3047 fprintf(stderr
, "*** somewhere in time ***\n");
3049 ufoBacktrace(ufoIP
, 1);
3051 ufoCurrState
= oldst
;
3055 // ////////////////////////////////////////////////////////////////////////// //
3056 // some init words, and PAD
3061 UFWORD(SP0_STORE
) { ufoSP
= 0; }
3066 if (ufoRP
!= ufoRPTop
) {
3068 // we need to push a dummy value
3069 ufoRPush(0xdeadf00d);
3075 // PAD is at the beginning of temp area
3077 ufoPush(UFO_PAD_ADDR
);
3081 // ////////////////////////////////////////////////////////////////////////// //
3082 // peeks and pokes with address register
3093 UFWORD(REGA_STORE
) {
3101 const uint32_t newa
= ufoPop();
3114 UFWORD(REGA_INC_CELL
) {
3127 ufoRegA
= ufoRPop();
3131 // ////////////////////////////////////////////////////////////////////////// //
3132 // useful to work with handles and normal addreses uniformly
3137 UFWORD(CPEEK_REGA_IDX
) {
3138 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3139 const uint32_t idx
= ufoPop();
3140 const uint32_t newaddr
= ufoRegA
+ idx
;
3141 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3142 ufoPush(ufoImgGetU8Ext(newaddr
));
3144 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3145 ufoRegA
, idx
, newaddr
);
3149 UFCALL(PAR_HANDLE_LOAD_BYTE
);
3155 UFWORD(WPEEK_REGA_IDX
) {
3156 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3157 const uint32_t idx
= ufoPop();
3158 const uint32_t newaddr
= ufoRegA
+ idx
;
3159 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3160 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3162 ufoPush(ufoImgGetU16(newaddr
));
3164 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3165 ufoRegA
, idx
, newaddr
);
3169 UFCALL(PAR_HANDLE_LOAD_WORD
);
3175 UFWORD(PEEK_REGA_IDX
) {
3176 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3177 const uint32_t idx
= ufoPop();
3178 const uint32_t newaddr
= ufoRegA
+ idx
;
3179 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3180 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3182 ufoPush(ufoImgGetU32(newaddr
));
3184 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3185 ufoRegA
, idx
, newaddr
);
3189 UFCALL(PAR_HANDLE_LOAD_CELL
);
3195 UFWORD(CPOKE_REGA_IDX
) {
3196 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3197 const uint32_t idx
= ufoPop();
3198 const uint32_t newaddr
= ufoRegA
+ idx
;
3199 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3200 const uint32_t value
= ufoPop();
3201 ufoImgPutU8(newaddr
, value
);
3203 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3204 ufoRegA
, idx
, newaddr
);
3208 UFCALL(PAR_HANDLE_STORE_BYTE
);
3214 UFWORD(WPOKE_REGA_IDX
) {
3215 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3216 const uint32_t idx
= ufoPop();
3217 const uint32_t newaddr
= ufoRegA
+ idx
;
3218 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3219 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3221 const uint32_t value
= ufoPop();
3222 ufoImgPutU16(newaddr
, value
);
3224 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3225 ufoRegA
, idx
, newaddr
);
3229 UFCALL(PAR_HANDLE_STORE_WORD
);
3235 UFWORD(POKE_REGA_IDX
) {
3236 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3237 const uint32_t idx
= ufoPop();
3238 const uint32_t newaddr
= ufoRegA
+ idx
;
3239 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3240 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3242 const uint32_t value
= ufoPop();
3243 ufoImgPutU32(newaddr
, value
);
3245 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3246 ufoRegA
, idx
, newaddr
);
3250 UFCALL(PAR_HANDLE_STORE_CELL
);
3255 // ////////////////////////////////////////////////////////////////////////// //
3260 // ( addr -- value8 )
3262 ufoPush(ufoImgGetU8Ext(ufoPop()));
3266 // ( addr -- value16 )
3268 const uint32_t addr
= ufoPop();
3269 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3270 ufoPush(ufoImgGetU16(addr
));
3274 UFCALL(PAR_HANDLE_LOAD_WORD
);
3279 // ( addr -- value32 )
3281 const uint32_t addr
= ufoPop();
3282 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3283 ufoPush(ufoImgGetU32(addr
));
3287 UFCALL(PAR_HANDLE_LOAD_CELL
);
3294 const uint32_t addr
= ufoPop();
3295 const uint32_t val
= ufoPop();
3296 ufoImgPutU8Ext(addr
, val
);
3300 // ( val16 addr -- )
3302 const uint32_t addr
= ufoPop();
3303 const uint32_t val
= ufoPop();
3304 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3305 ufoImgPutU16(addr
, val
);
3310 UFCALL(PAR_HANDLE_STORE_WORD
);
3315 // ( val32 addr -- )
3317 const uint32_t addr
= ufoPop();
3318 const uint32_t val
= ufoPop();
3319 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
3320 ufoImgPutU32(addr
, val
);
3325 UFCALL(PAR_HANDLE_STORE_CELL
);
3330 // ////////////////////////////////////////////////////////////////////////// //
3331 // dictionary emitters
3336 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
3340 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
3344 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
3347 // ////////////////////////////////////////////////////////////////////////// //
3353 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3357 // (LITCFA) ( -- n )
3358 UFWORD(PAR_LITCFA
) {
3359 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3363 // (LITVOCID) ( -- n )
3364 UFWORD(PAR_LITVOCID
) {
3365 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
3370 UFWORD(PAR_LITSTR8
) {
3371 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
3374 ufoIP
+= count
+ 1; // 1 for terminating 0
3376 ufoIP
= UFO_ALIGN4(ufoIP
);
3380 // ////////////////////////////////////////////////////////////////////////// //
3385 UFWORD(PAR_BRANCH
) {
3386 ufoIP
= ufoImgGetU32(ufoIP
);
3389 // (TBRANCH) ( flag )
3390 UFWORD(PAR_TBRANCH
) {
3392 ufoIP
= ufoImgGetU32(ufoIP
);
3398 // (0BRANCH) ( flag )
3399 UFWORD(PAR_0BRANCH
) {
3401 ufoIP
= ufoImgGetU32(ufoIP
);
3407 // (+0BRANCH) ( flag )
3408 UFWORD(PAR_P0BRANCH
) {
3409 if ((ufoPop() & 0x80000000u
) == 0) {
3410 ufoIP
= ufoImgGetU32(ufoIP
);
3416 // (+BRANCH) ( flag )
3417 UFWORD(PAR_PBRANCH
) {
3418 const uint32_t v
= ufoPop();
3419 if (v
> 0 && v
< 0x80000000u
) {
3420 ufoIP
= ufoImgGetU32(ufoIP
);
3426 // (-0BRANCH) ( flag )
3427 UFWORD(PAR_M0BRANCH
) {
3428 const uint32_t v
= ufoPop();
3429 if (v
== 0 || v
>= 0x80000000u
) {
3430 ufoIP
= ufoImgGetU32(ufoIP
);
3436 // (-BRANCH) ( flag )
3437 UFWORD(PAR_MBRANCH
) {
3438 if ((ufoPop() & 0x80000000u
) != 0) {
3439 ufoIP
= ufoImgGetU32(ufoIP
);
3445 // (DATASKIP) ( -- )
3446 UFWORD(PAR_DATASKIP
) {
3447 ufoIP
+= ufoImgGetU32(ufoIP
) + 4u;
3451 // ////////////////////////////////////////////////////////////////////////// //
3452 // execute words by CFA
3461 // EXECUTE-TAIL ( cfa )
3462 UFWORD(EXECUTE_TAIL
) {
3469 // ////////////////////////////////////////////////////////////////////////// //
3470 // word termination, locals support
3480 UFWORD(PAR_LENTER
) {
3481 // low byte of loccount is total number of locals
3482 // high byte is the number of args
3483 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3484 uint32_t acount
= (lcount
>> 8) & 0xff;
3486 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3487 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3488 ufoFatal("out of locals stack");
3491 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3492 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3493 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3494 ufoLBP
= newbp
; ufoLP
+= lcount
;
3497 while (newbp
!= ufoLBP
) {
3498 ufoLStack
[newbp
] = ufoPop();
3504 UFWORD(PAR_LLEAVE
) {
3505 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3506 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3508 ufoLBP
= ufoLStack
[ufoLBP
];
3511 //==========================================================================
3515 //==========================================================================
3516 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
3517 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3518 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3519 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3522 //==========================================================================
3526 //==========================================================================
3527 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
3528 const uint32_t value
= ufoPop();
3529 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3530 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3531 ufoLStack
[ufoLBP
+ lidx
] = value
;
3536 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3540 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3543 // ////////////////////////////////////////////////////////////////////////// //
3544 // stack manipulation
3549 UFWORD(DUP
) { ufoDup(); }
3551 // ( n -- n n ) | ( 0 -- 0 )
3552 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3554 // ( n0 n1 -- n0 n1 n0 n1 )
3555 UFWORD(DDUP
) { ufo2Dup(); }
3558 UFWORD(DROP
) { ufoDrop(); }
3561 UFWORD(DDROP
) { ufo2Drop(); }
3563 // ( n0 n1 -- n1 n0 )
3564 UFWORD(SWAP
) { ufoSwap(); }
3566 // ( n0 n1 -- n1 n0 )
3567 UFWORD(DSWAP
) { ufo2Swap(); }
3569 // ( n0 n1 -- n0 n1 n0 )
3570 UFWORD(OVER
) { ufoOver(); }
3572 // ( n0 n1 -- n0 n1 n0 )
3573 UFWORD(DOVER
) { ufo2Over(); }
3575 // ( n0 n1 n2 -- n1 n2 n0 )
3576 UFWORD(ROT
) { ufoRot(); }
3578 // ( n0 n1 n2 -- n2 n0 n1 )
3579 UFWORD(NROT
) { ufoNRot(); }
3583 UFWORD(RDUP
) { ufoRDup(); }
3586 UFWORD(RDROP
) { ufoRDrop(); }
3590 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3593 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3596 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3601 const uint32_t n
= ufoPop();
3602 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3603 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3609 const uint32_t n
= ufoPop();
3610 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3611 const uint32_t rp
= ufoRP
- n
- 1u;
3612 ufoPush(ufoRStack
[rp
]);
3618 const uint32_t n
= ufoPop();
3619 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3621 case 0: break; // do nothing
3622 case 1: ufoSwap(); break;
3623 case 2: ufoRot(); break;
3626 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3627 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3628 ufoDStack
[ufoSP
- 1u] = val
;
3637 const uint32_t n
= ufoPop();
3638 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3640 const uint32_t rp
= ufoRP
- n
- 1u;
3641 const uint32_t val
= ufoRStack
[rp
];
3642 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3643 ufoRStack
[ufoRP
- 1u] = val
;
3648 // ( | a b -- | b a )
3650 const uint32_t b
= ufoRPop();
3651 const uint32_t a
= ufoRPop();
3652 ufoRPush(b
); ufoRPush(a
);
3656 // ( | a b -- | a b a )
3658 const uint32_t b
= ufoRPop();
3659 const uint32_t a
= ufoRPop();
3660 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3664 // ( | a b c -- | b c a )
3666 const uint32_t c
= ufoRPop();
3667 const uint32_t b
= ufoRPop();
3668 const uint32_t a
= ufoRPop();
3669 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3673 // ( | a b c -- | c a b )
3675 const uint32_t c
= ufoRPop();
3676 const uint32_t b
= ufoRPop();
3677 const uint32_t a
= ufoRPop();
3678 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3682 // ////////////////////////////////////////////////////////////////////////// //
3689 ufoPushBool(ufoLoadNextLine(1));
3694 UFWORD(REFILL_NOCROSS
) {
3695 ufoPushBool(ufoLoadNextLine(0));
3701 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3706 UFWORD(TIB_PEEKCH
) {
3707 ufoPush(ufoTibPeekCh());
3712 UFWORD(TIB_PEEKCH_OFS
) {
3713 const uint32_t ofs
= ufoPop();
3714 ufoPush(ufoTibPeekChOfs(ofs
));
3720 ufoPush(ufoTibGetCh());
3725 UFWORD(TIB_SKIPCH
) {
3730 // ////////////////////////////////////////////////////////////////////////// //
3734 //==========================================================================
3738 //==========================================================================
3739 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3740 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3744 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3745 // does base TIB parsing; never copies anything.
3746 // as our reader is line-based, returns FALSE on EOL.
3747 // EOL is detected after skipping leading delimiters.
3748 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3749 // trailing delimiter is always skipped.
3751 const uint32_t skipDelim
= ufoPop();
3752 const uint32_t delim
= ufoPop();
3755 if (delim
== 0 || delim
> 0xffU
) {
3757 while (ufoTibGetCh() != 0) {}
3760 ch
= ufoTibPeekCh();
3761 // skip initial delimiters
3763 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3765 ch
= ufoTibPeekCh();
3772 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3774 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3777 ch
= ufoTibPeekCh();
3780 if (ch
!= 0) ufoTibSkipCh();
3788 // PARSE-SKIP-BLANKS
3790 UFWORD(PARSE_SKIP_BLANKS
) {
3791 uint8_t ch
= ufoTibPeekCh();
3792 while (ch
!= 0 && ch
<= 32) {
3794 ch
= ufoTibPeekCh();
3798 //==========================================================================
3800 // ufoParseMLComment
3802 // initial two chars are skipped
3804 //==========================================================================
3805 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3808 while (level
!= 0) {
3812 UFCALL(REFILL_NOCROSS
);
3813 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3815 ufoFatal("unexpected end of line in comment");
3818 ch1
= ufoTibPeekCh();
3819 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3820 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3821 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3826 // (PARSE-SKIP-COMMENTS)
3827 // ( allow-multiline? -- )
3828 // skip all blanks and comments
3829 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3830 const uint32_t allowMulti
= ufoPop();
3832 ch
= ufoTibPeekCh();
3834 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3839 ch
= ufoTibPeekCh();
3841 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3843 } else if (ch
== '(') {
3845 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3846 ufoTibPeekChOfs(0));
3848 ch1
= ufoTibPeekChOfs(1);
3850 // single-line comment
3851 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3852 ch
= ufoTibPeekCh();
3853 } else if ((ch1
== '*' || ch1
== '(') && ufoTibPeekChOfs(2) <= 32) {
3854 // possibly multiline
3855 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3856 ufoParseMLComment(allowMulti
, (ch1
== '('));
3857 ch
= ufoTibPeekCh();
3861 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3862 // single-line comment
3863 while (ch
!= 0) ch
= ufoTibGetCh();
3864 } else if (ch
== '-' && ufoTibPeekChOfs(1) == ch
&& ufoTibPeekChOfs(2) <= 32) {
3866 while (ch
!= 0) ch
= ufoTibGetCh();
3867 } else if ((ch
== ';' || ch
== '/') && ufoTibPeekChOfs(1) == ch
) {
3869 while (ch
!= 0) ch
= ufoTibGetCh();
3875 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3881 UFWORD(PARSE_SKIP_LINE
) {
3882 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3883 if (ufoPop() != 0) {
3889 // ( -- addr count )
3890 // parse with leading blanks skipping. doesn't copy anything.
3891 // return empty string on EOL.
3892 UFWORD(PARSE_NAME
) {
3893 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3894 if (ufoPop() == 0) {
3901 // ( delim -- addr count TRUE / FALSE )
3902 // parse without skipping delimiters; never copies anything.
3903 // as our reader is line-based, returns FALSE on EOL.
3904 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3905 // trailing delimiter is always skipped.
3907 ufoPushBool(0); UFCALL(PAR_PARSE
);
3911 // ////////////////////////////////////////////////////////////////////////// //
3917 UFWORD(PAR_NORM_EMIT_CHAR
) {
3918 uint32_t ch
= ufoPop()&0xffU
;
3919 if (ch
< 32 || ch
== 127) {
3920 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
3925 // (NORM-XEMIT-CHAR)
3927 UFWORD(PAR_NORM_XEMIT_CHAR
) {
3928 uint32_t ch
= ufoPop()&0xffU
;
3929 if (ch
< 32 || ch
== 127) ch
= '?';
3936 uint32_t ch
= ufoPop()&0xffU
;
3937 ufoLastEmitWasCR
= (ch
== 10);
3944 ufoPushBool(ufoLastEmitWasCR
);
3950 ufoLastEmitWasCR
= !!ufoPop();
3955 UFWORD(FLUSH_EMIT
) {
3960 // ////////////////////////////////////////////////////////////////////////// //
3964 #define UF_UMATH(name_,op_) \
3966 const uint32_t a = ufoPop(); \
3970 #define UF_BMATH(name_,op_) \
3972 const uint32_t b = ufoPop(); \
3973 const uint32_t a = ufoPop(); \
3977 #define UF_BDIV(name_,op_) \
3979 const uint32_t b = ufoPop(); \
3980 const uint32_t a = ufoPop(); \
3981 if (b == 0) ufoFatal("division by zero"); \
3985 #define UFO_POP_U64() ({ \
3986 const uint32_t hi_ = ufoPop(); \
3987 const uint32_t lo_ = ufoPop(); \
3988 (((uint64_t)hi_ << 32) | lo_); \
3991 // this is UB by the idiotic C standard. i don't care.
3992 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
3994 #define UFO_PUSH_U64(vn_) do { \
3995 ufoPush((uint32_t)(vn_)); \
3996 ufoPush((uint32_t)((vn_) >> 32)); \
3999 // this is UB by the idiotic C standard. i don't care.
4000 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
4004 UF_BMATH(PLUS
, a
+ b
);
4008 UF_BMATH(MINUS
, a
- b
);
4012 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
4016 UF_BMATH(UMUL
, a
* b
);
4020 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
4024 UF_BDIV(UDIV
, a
/ b
);
4028 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
4032 UF_BDIV(UMOD
, a
% b
);
4035 // ( a b -- a/b, a%b )
4037 const int32_t b
= (int32_t)ufoPop();
4038 const int32_t a
= (int32_t)ufoPop();
4039 if (b
== 0) ufoFatal("division by zero");
4040 ufoPush((uint32_t)(a
/b
));
4041 ufoPush((uint32_t)(a
%b
));
4045 // ( a b -- a/b, a%b )
4047 const uint32_t b
= ufoPop();
4048 const uint32_t a
= ufoPop();
4049 if (b
== 0) ufoFatal("division by zero");
4050 ufoPush((uint32_t)(a
/b
));
4051 ufoPush((uint32_t)(a
%b
));
4055 // ( a b c -- a*b/c )
4056 // this uses 64-bit intermediate value
4058 const int32_t c
= (int32_t)ufoPop();
4059 const int32_t b
= (int32_t)ufoPop();
4060 const int32_t a
= (int32_t)ufoPop();
4061 if (c
== 0) ufoFatal("division by zero");
4062 int64_t xval
= a
; xval
*= b
; xval
/= c
;
4063 ufoPush((uint32_t)(int32_t)xval
);
4067 // ( a b c -- a*b/c )
4068 // this uses 64-bit intermediate value
4070 const uint32_t c
= ufoPop();
4071 const uint32_t b
= ufoPop();
4072 const uint32_t a
= ufoPop();
4073 if (c
== 0) ufoFatal("division by zero");
4074 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
4075 ufoPush((uint32_t)xval
);
4079 // ( a b c -- a*b/c a*b%c )
4080 // this uses 64-bit intermediate value
4082 const int32_t c
= (int32_t)ufoPop();
4083 const int32_t b
= (int32_t)ufoPop();
4084 const int32_t a
= (int32_t)ufoPop();
4085 if (c
== 0) ufoFatal("division by zero");
4086 int64_t xval
= a
; xval
*= b
;
4087 ufoPush((uint32_t)(int32_t)(xval
/ c
));
4088 ufoPush((uint32_t)(int32_t)(xval
% c
));
4092 // ( a b c -- a*b/c )
4093 // this uses 64-bit intermediate value
4094 UFWORD(UMULDIVMOD
) {
4095 const uint32_t c
= ufoPop();
4096 const uint32_t b
= ufoPop();
4097 const uint32_t a
= ufoPop();
4098 if (c
== 0) ufoFatal("division by zero");
4099 uint64_t xval
= a
; xval
*= b
;
4100 ufoPush((uint32_t)(xval
/ c
));
4101 ufoPush((uint32_t)(xval
% c
));
4105 // ( a b -- lo(a*b) hi(a*b) )
4106 // this leaves 64-bit result
4108 const int32_t b
= (int32_t)ufoPop();
4109 const int32_t a
= (int32_t)ufoPop();
4110 int64_t xval
= a
; xval
*= b
;
4115 // ( a b -- lo(a*b) hi(a*b) )
4116 // this leaves 64-bit result
4118 const uint32_t b
= ufoPop();
4119 const uint32_t a
= ufoPop();
4120 uint64_t xval
= a
; xval
*= b
;
4125 // ( alo ahi b -- a/b a%b )
4127 const int32_t b
= (int32_t)ufoPop();
4128 if (b
== 0) ufoFatal("division by zero");
4129 int64_t a
= UFO_POP_I64();
4130 int32_t adiv
= (int32_t)(a
/ b
);
4131 int32_t amod
= (int32_t)(a
% b
);
4132 ufoPush((uint32_t)adiv
);
4133 ufoPush((uint32_t)amod
);
4137 // ( alo ahi b -- a/b a%b )
4139 const uint32_t b
= ufoPop();
4140 if (b
== 0) ufoFatal("division by zero");
4141 uint64_t a
= UFO_POP_U64();
4142 uint32_t adiv
= (uint32_t)(a
/ b
);
4143 uint32_t amod
= (uint32_t)(a
% b
);
4149 // ( alo ahi u -- lo hi )
4151 const uint32_t b
= ufoPop();
4152 uint64_t a
= UFO_POP_U64();
4158 // ( lo0 hi0 lo1 hi1 -- lo hi )
4160 uint64_t n1
= UFO_POP_U64();
4161 uint64_t n0
= UFO_POP_U64();
4167 // ( lo0 hi0 lo1 hi1 -- lo hi )
4169 uint64_t n1
= UFO_POP_U64();
4170 uint64_t n0
= UFO_POP_U64();
4176 // ( lo0 hi0 lo1 hi1 -- bool )
4178 uint64_t n1
= UFO_POP_U64();
4179 uint64_t n0
= UFO_POP_U64();
4180 ufoPushBool(n0
== n1
);
4184 // ( lo0 hi0 lo1 hi1 -- bool )
4186 int64_t n1
= UFO_POP_I64();
4187 int64_t n0
= UFO_POP_I64();
4188 ufoPushBool(n0
< n1
);
4192 // ( lo0 hi0 lo1 hi1 -- bool )
4194 int64_t n1
= UFO_POP_I64();
4195 int64_t n0
= UFO_POP_I64();
4196 ufoPushBool(n0
<= n1
);
4200 // ( lo0 hi0 lo1 hi1 -- bool )
4202 uint64_t n1
= UFO_POP_U64();
4203 uint64_t n0
= UFO_POP_U64();
4204 ufoPushBool(n0
< n1
);
4208 // ( lo0 hi0 lo1 hi1 -- bool )
4210 uint64_t n1
= UFO_POP_U64();
4211 uint64_t n0
= UFO_POP_U64();
4212 ufoPushBool(n0
<= n1
);
4216 // ( dlo dhi n -- nmod ndiv )
4217 // rounds toward zero
4219 const int32_t n
= (int32_t)ufoPop();
4220 if (n
== 0) ufoFatal("division by zero");
4221 int64_t d
= UFO_POP_I64();
4222 int32_t ndiv
= (int32_t)(d
/ n
);
4223 int32_t nmod
= (int32_t)(d
% n
);
4229 // ( dlo dhi n -- nmod ndiv )
4230 // rounds toward negative infinity
4232 const int32_t n
= (int32_t)ufoPop();
4233 if (n
== 0) ufoFatal("division by zero");
4234 int64_t d
= UFO_POP_I64();
4235 int32_t ndiv
= (int32_t)(d
/ n
);
4236 int32_t nmod
= (int32_t)(d
% n
);
4237 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
4246 // ////////////////////////////////////////////////////////////////////////// //
4247 // simple logic and bit manipulation
4250 #define UF_CMP(name_,op_) \
4252 const uint32_t b = ufoPop(); \
4253 const uint32_t a = ufoPop(); \
4259 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
4263 UF_CMP(ULESS
, a
< b
);
4267 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
4271 UF_CMP(UGREAT
, a
> b
);
4275 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
4279 UF_CMP(ULESSEQU
, a
<= b
);
4283 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
4287 UF_CMP(UGREATEQU
, a
>= b
);
4291 UF_CMP(EQU
, a
== b
);
4295 UF_CMP(NOTEQU
, a
!= b
);
4300 const uint32_t a
= ufoPop();
4301 ufoPushBool(a
== 0);
4306 UFWORD(ZERO_NOTEQU
) {
4307 const uint32_t a
= ufoPop();
4308 ufoPushBool(a
!= 0);
4313 UF_CMP(LOGAND
, a
&& b
);
4317 UF_CMP(LOGOR
, a
|| b
);
4322 const uint32_t b
= ufoPop();
4323 const uint32_t a
= ufoPop();
4330 const uint32_t b
= ufoPop();
4331 const uint32_t a
= ufoPop();
4338 const uint32_t b
= ufoPop();
4339 const uint32_t a
= ufoPop();
4346 const uint32_t a
= ufoPop();
4352 // arithmetic shift; positive `n` shifts to the left
4354 int32_t c
= (int32_t)ufoPop();
4357 int32_t n
= (int32_t)ufoPop();
4359 if (n
< 0) n
= -1; else n
= 0;
4361 n
>>= (uint8_t)(-c
);
4363 ufoPush((uint32_t)n
);
4366 uint32_t u
= ufoPop();
4378 // logical shift; positive `n` shifts to the left
4380 int32_t c
= (int32_t) ufoPop();
4381 uint32_t u
= ufoPop();
4387 u
>>= (uint8_t)(-c
);
4401 // ////////////////////////////////////////////////////////////////////////// //
4402 // string unescaping
4406 // ( addr count -- addr count )
4407 UFWORD(PAR_UNESCAPE
) {
4408 const uint32_t count
= ufoPop();
4409 const uint32_t addr
= ufoPeek();
4410 if ((count
& ((uint32_t)1<<31)) == 0) {
4411 const uint32_t eaddr
= addr
+ count
;
4412 uint32_t caddr
= addr
;
4413 uint32_t daddr
= addr
;
4414 while (caddr
!= eaddr
) {
4415 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4416 if (ch
== '\\' && caddr
!= eaddr
) {
4417 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4419 case 'r': ch
= '\r'; break;
4420 case 'n': ch
= '\n'; break;
4421 case 't': ch
= '\t'; break;
4422 case 'e': ch
= '\x1b'; break;
4423 case '`': ch
= '"'; break; // special escape to insert double-quote
4424 case '"': ch
= '"'; break;
4425 case '\\': ch
= '\\'; break;
4427 if (eaddr
- daddr
>= 1) {
4428 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
4429 if (dg0
< 0) ufoFatal("invalid hex string escape");
4430 if (eaddr
- daddr
>= 2) {
4431 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
4432 if (dg1
< 0) ufoFatal("invalid hex string escape");
4433 ch
= (uint8_t)(dg0
* 16 + dg1
);
4440 ufoFatal("invalid hex string escape");
4443 default: ufoFatal("invalid string escape");
4446 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
4448 ufoPush(daddr
- addr
);
4455 // ////////////////////////////////////////////////////////////////////////// //
4456 // numeric conversions
4459 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4460 UFWORD(PAR_BASED_NUMBER
) {
4461 const uint32_t xbase
= ufoPop();
4462 const uint32_t allowSign
= ufoPop();
4463 int32_t count
= (int32_t)ufoPop();
4464 uint32_t addr
= ufoPop();
4470 if (allowSign
&& count
> 1) {
4471 ch
= ufoImgGetU8Ext(addr
);
4472 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
4473 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
4476 // special-based numbers
4477 ch
= ufoImgGetU8Ext(addr
);
4478 if (count
>= 3 && ch
== '0') {
4479 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4480 case 'x': case 'X': base
= 16; break;
4481 case 'o': case 'O': base
= 8; break;
4482 case 'b': case 'B': base
= 2; break;
4483 case 'd': case 'D': base
= 10; break;
4486 if (base
&& digitInBase((char)ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u), base
) >= 0) {
4487 addr
+= 2; count
-= 2;
4491 } else if (count
>= 2 && ch
== '$') {
4493 addr
+= 1u; count
-= 1;
4494 } else if (count
>= 2 && ch
== '#') {
4496 addr
+= 1u; count
-= 1;
4497 } else if (count
>= 2 && ch
== '%') {
4499 addr
+= 1u; count
-= 1;
4500 } else if (count
>= 3 && ch
== '&') {
4501 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4502 case 'h': case 'H': base
= 16; break;
4503 case 'o': case 'O': base
= 8; break;
4504 case 'b': case 'B': base
= 2; break;
4505 case 'd': case 'D': base
= 10; break;
4508 if (base
) { addr
+= 2u; count
-= 2; }
4510 if (!base
&& count
> 2 && ch
>= '0' && ch
<= '9') {
4511 ch
= ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u);
4513 case 'b': case 'B': if (xbase
< 12) base
= 2; break;
4514 case 'o': case 'O': if (xbase
< 25) base
= 8; break;
4515 case 'h': case 'H': if (xbase
< 18) base
= 16; break;
4517 if (base
) count
-= 1;
4521 if (!base
&& xbase
< 255) base
= xbase
;
4523 if (count
<= 0 || base
< 1 || base
> 36) {
4527 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
4528 while (!error
&& count
!= 0) {
4529 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
4531 error
= 1; wasUnder
= 0; wasDig
= 1;
4532 dig
= digitInBase((char)ch
, (int)base
);
4534 nc
= n
* (uint32_t)base
;
4536 nc
+= (uint32_t)dig
;
4549 if (!error
&& wasDig
&& !wasUnder
) {
4550 if (allowSign
&& neg
) n
= ~n
+ 1u;
4560 // ////////////////////////////////////////////////////////////////////////// //
4561 // compiler-related, dictionary-related
4564 static char ufoWNameBuf
[256];
4566 // (CREATE-WORD-HEADER)
4567 // ( addr count word-flags -- )
4568 UFWORD(PAR_CREATE_WORD_HEADER
) {
4569 const uint32_t flags
= ufoPop();
4570 const uint32_t wlen
= ufoPop();
4571 const uint32_t waddr
= ufoPop();
4572 if (wlen
== 0) ufoFatal("word name expected");
4573 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4574 // copy to separate buffer
4575 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4576 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4578 ufoWNameBuf
[wlen
] = 0;
4579 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4582 // (CREATE-NAMELESS-WORD-HEADER)
4583 // ( word-flags -- )
4584 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4585 const uint32_t flags
= ufoPop();
4586 ufoCreateWordHeader("", flags
);
4590 // ( addr count -- cfa TRUE / FALSE)
4592 const uint32_t wlen
= ufoPop();
4593 const uint32_t waddr
= ufoPop();
4594 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4595 // copy to separate buffer
4596 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4597 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4599 ufoWNameBuf
[wlen
] = 0;
4600 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4612 // (FIND-WORD-IN-VOC)
4613 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4614 // find only in the given voc; no name resolution
4615 UFWORD(FIND_WORD_IN_VOC
) {
4616 const uint32_t allowHidden
= ufoPop();
4617 const uint32_t vocid
= ufoPop();
4618 const uint32_t wlen
= ufoPop();
4619 const uint32_t waddr
= ufoPop();
4620 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4621 // copy to separate buffer
4622 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4623 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4625 ufoWNameBuf
[wlen
] = 0;
4626 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4638 // (FIND-WORD-IN-VOC-AND-PARENTS)
4639 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4640 // find only in the given voc; no name resolution
4641 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4642 const uint32_t allowHidden
= ufoPop();
4643 const uint32_t vocid
= ufoPop();
4644 const uint32_t wlen
= ufoPop();
4645 const uint32_t waddr
= ufoPop();
4646 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4647 // copy to separate buffer
4648 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4649 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4651 ufoWNameBuf
[wlen
] = 0;
4652 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4665 // ////////////////////////////////////////////////////////////////////////// //
4666 // more compiler words
4669 // ////////////////////////////////////////////////////////////////////////// //
4670 // vocabulary and wordlist utilities
4675 UFWORD(PAR_GET_VSP
) {
4681 UFWORD(PAR_SET_VSP
) {
4682 const uint32_t vsp
= ufoPop();
4683 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4689 UFWORD(PAR_VSP_LOAD
) {
4690 const uint32_t vsp
= ufoPop();
4691 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4692 ufoPush(ufoVocStack
[vsp
]);
4697 UFWORD(PAR_VSP_STORE
) {
4698 const uint32_t vsp
= ufoPop();
4699 const uint32_t value
= ufoPop();
4700 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4701 ufoVocStack
[vsp
] = value
;
4705 // ////////////////////////////////////////////////////////////////////////// //
4706 // word field address conversion
4712 const uint32_t cfa
= ufoPop();
4713 ufoPush(UFO_CFA_TO_PFA(cfa
));
4719 const uint32_t cfa
= ufoPop();
4720 ufoPush(UFO_CFA_TO_NFA(cfa
));
4726 const uint32_t cfa
= ufoPop();
4727 ufoPush(UFO_CFA_TO_LFA(cfa
));
4731 // ( cfa -- wend-addr )
4733 const uint32_t cfa
= ufoPop();
4734 ufoPush(ufoGetWordEndAddr(cfa
));
4740 const uint32_t pfa
= ufoPop();
4741 ufoPush(UFO_PFA_TO_CFA(pfa
));
4747 const uint32_t pfa
= ufoPop();
4748 const uint32_t cfa
= UFO_PFA_TO_CFA(pfa
);
4749 ufoPush(UFO_CFA_TO_NFA(cfa
));
4755 const uint32_t nfa
= ufoPop();
4756 ufoPush(UFO_NFA_TO_CFA(nfa
));
4762 const uint32_t nfa
= ufoPop();
4763 const uint32_t cfa
= UFO_NFA_TO_CFA(nfa
);
4764 ufoPush(UFO_CFA_TO_PFA(cfa
));
4770 const uint32_t nfa
= ufoPop();
4771 ufoPush(UFO_NFA_TO_LFA(nfa
));
4777 const uint32_t lfa
= ufoPop();
4778 ufoPush(UFO_LFA_TO_CFA(lfa
));
4784 const uint32_t lfa
= ufoPop();
4785 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4786 ufoPush(UFO_CFA_TO_PFA(cfa
));
4792 const uint32_t lfa
= ufoPop();
4793 ufoPush(UFO_LFA_TO_BFA(lfa
));
4799 const uint32_t lfa
= ufoPop();
4800 ufoPush(UFO_LFA_TO_XFA(lfa
));
4806 const uint32_t lfa
= ufoPop();
4807 ufoPush(UFO_LFA_TO_YFA(lfa
));
4813 const uint32_t lfa
= ufoPop();
4814 ufoPush(UFO_LFA_TO_NFA(lfa
));
4818 // ( ip -- nfa / 0 )
4820 const uint32_t ip
= ufoPop();
4821 ufoPush(ufoFindWordForIP(ip
));
4825 // ( ip -- addr count line TRUE / FALSE )
4826 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4827 UFWORD(IP2FILELINE
) {
4828 const uint32_t ip
= ufoPop();
4830 const char *fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
4831 if (fname
!= NULL
) {
4833 uint32_t addr
= ufoPeek();
4835 while (*fname
!= 0) {
4836 ufoImgPutU8(addr
, *(const unsigned char *)fname
);
4837 fname
+= 1u; addr
+= 1u; count
+= 1u;
4839 ufoImgPutU8(addr
, 0); // just in case
4849 // IP->FILE-HASH/LINE
4850 // ( ip -- len hash line TRUE / FALSE )
4851 UFWORD(IP2FILEHASHLINE
) {
4852 const uint32_t ip
= ufoPop();
4853 uint32_t fline
, fhash
, flen
;
4854 const char *fname
= ufoFindFileForIP(ip
, &fline
, &flen
, &fhash
);
4855 if (fname
!= NULL
) {
4866 // ////////////////////////////////////////////////////////////////////////// //
4867 // string operations
4870 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4871 uint32_t hash
= 0x29a;
4872 if ((size
& ((uint32_t)1<<31)) == 0) {
4874 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4877 addr
+= 1u; size
-= 1u;
4887 //==========================================================================
4891 //==========================================================================
4892 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
4894 if ((count
& ((uint32_t)1<<31)) == 0) {
4896 while (res
!= 0 && count
!= 0) {
4897 res
= (toUpperU8(ufoImgGetU8Ext(addr0
)) == toUpperU8(ufoImgGetU8Ext(addr1
)));
4898 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
4907 // ( a0 c0 a1 c1 -- bool )
4909 int32_t c1
= (int32_t)ufoPop();
4910 uint32_t a1
= ufoPop();
4911 int32_t c0
= (int32_t)ufoPop();
4912 uint32_t a0
= ufoPop();
4917 while (res
!= 0 && c0
!= 0) {
4918 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4919 a0
+= 1; a1
+= 1; c0
-= 1;
4928 // ( a0 c0 a1 c1 -- bool )
4930 int32_t c1
= (int32_t)ufoPop();
4931 uint32_t a1
= ufoPop();
4932 int32_t c0
= (int32_t)ufoPop();
4933 uint32_t a0
= ufoPop();
4938 while (res
!= 0 && c0
!= 0) {
4939 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4940 a0
+= 1; a1
+= 1; c0
-= 1;
4948 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4949 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4950 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4951 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4953 const uint32_t pcount
= ufoPop();
4954 const uint32_t paddr
= ufoPop();
4955 const uint32_t tcount
= ufoPop();
4956 const uint32_t taddr
= ufoPop();
4957 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
4958 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
4959 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
4961 ufoPush(tcount
- f
);
4973 // ( addr count -- hash )
4975 uint32_t count
= ufoPop();
4976 uint32_t addr
= ufoPop();
4977 ufoPush(ufoHashBuf(addr
, count
, 0));
4981 // ( addr count -- hash )
4983 uint32_t count
= ufoPop();
4984 uint32_t addr
= ufoPop();
4985 ufoPush(ufoHashBuf(addr
, count
, 0x20));
4989 // ////////////////////////////////////////////////////////////////////////// //
4990 // conditional defines
4993 typedef struct UForthCondDefine_t UForthCondDefine
;
4994 struct UForthCondDefine_t
{
4998 UForthCondDefine
*next
;
5001 static UForthCondDefine
*ufoCondDefines
= NULL
;
5002 static char ufoErrMsgBuf
[4096];
5005 //==========================================================================
5009 //==========================================================================
5010 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
5011 const unsigned char *s0
= (const unsigned char *)str0
;
5012 const unsigned char *s1
= (const unsigned char *)str1
;
5013 while (*s0
&& *s1
) {
5014 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
5017 return (*s0
== 0 && *s1
== 0);
5021 //==========================================================================
5025 //==========================================================================
5026 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
5028 if ((count
& ((uint32_t)1<<31)) == 0) {
5029 const unsigned char *src
= (const unsigned char *)buf
;
5031 while (res
!= 0 && count
!= 0) {
5032 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
5033 src
+= 1; addr
+= 1u; count
-= 1u;
5042 //==========================================================================
5044 // ufoClearCondDefines
5046 //==========================================================================
5047 static void ufoClearCondDefines (void) {
5048 while (ufoCondDefines
) {
5049 UForthCondDefine
*df
= ufoCondDefines
;
5050 ufoCondDefines
= df
->next
;
5051 if (df
->name
) free(df
->name
);
5057 //==========================================================================
5061 //==========================================================================
5062 int ufoHasCondDefine (const char *name
) {
5064 if (name
!= NULL
&& name
[0] != 0) {
5065 const size_t nlen
= strlen(name
);
5067 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5068 UForthCondDefine
*dd
= ufoCondDefines
;
5069 while (res
== 0 && dd
!= NULL
) {
5070 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5071 res
= ufoStrEquCI(name
, dd
->name
);
5081 //==========================================================================
5085 //==========================================================================
5086 void ufoCondDefine (const char *name
) {
5087 if (name
!= NULL
&& name
[0] != 0) {
5088 const size_t nlen
= strlen(name
);
5089 if (nlen
> 255) ufoFatal("conditional define name too long");
5090 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5091 UForthCondDefine
*dd
= ufoCondDefines
;
5093 while (res
== 0 && dd
!= NULL
) {
5094 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5095 res
= ufoStrEquCI(name
, dd
->name
);
5101 dd
= calloc(1, sizeof(UForthCondDefine
));
5102 if (dd
== NULL
) ufoFatal("out of memory for defines");
5103 dd
->name
= strdup(name
);
5104 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5105 dd
->namelen
= (uint32_t)nlen
;
5107 dd
->next
= ufoCondDefines
;
5108 ufoCondDefines
= dd
;
5114 //==========================================================================
5118 //==========================================================================
5119 void ufoCondUndef (const char *name
) {
5120 if (name
!= NULL
&& name
[0] != 0) {
5121 const size_t nlen
= strlen(name
);
5123 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5124 UForthCondDefine
*dd
= ufoCondDefines
;
5125 UForthCondDefine
*prev
= NULL
;
5126 while (dd
!= NULL
) {
5127 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5128 if (ufoStrEquCI(name
, dd
->name
)) {
5129 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
5135 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
5143 // ( addr count -- )
5144 UFWORD(PAR_DLR_DEFINE
) {
5145 uint32_t count
= ufoPop();
5146 uint32_t addr
= ufoPop();
5147 if (count
== 0) ufoFatal("empty define");
5148 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5149 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5150 UForthCondDefine
*dd
;
5151 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5152 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5153 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
5157 dd
= calloc(1, sizeof(UForthCondDefine
));
5158 if (dd
== NULL
) ufoFatal("out of memory for defines");
5159 dd
->name
= calloc(1, count
+ 1u);
5160 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5161 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5162 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5164 dd
->namelen
= count
;
5166 dd
->next
= ufoCondDefines
;
5167 ufoCondDefines
= dd
;
5171 // ( addr count -- )
5172 UFWORD(PAR_DLR_UNDEF
) {
5173 uint32_t count
= ufoPop();
5174 uint32_t addr
= ufoPop();
5175 if (count
== 0) ufoFatal("empty define");
5176 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5177 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5178 UForthCondDefine
*prev
= NULL
;
5179 UForthCondDefine
*dd
;
5180 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
5181 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5182 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
5183 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
5193 // ( addr count -- bool )
5194 UFWORD(PAR_DLR_DEFINEDQ
) {
5195 uint32_t count
= ufoPop();
5196 uint32_t addr
= ufoPop();
5197 if (count
== 0) ufoFatal("empty define");
5198 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5199 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5201 UForthCondDefine
*dd
= ufoCondDefines
;
5202 while (!found
&& dd
!= NULL
) {
5203 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5204 found
= ufoBufEquCI(addr
, count
, dd
->name
);
5212 // ////////////////////////////////////////////////////////////////////////// //
5217 // ( addr count -- )
5219 uint32_t count
= ufoPop();
5220 uint32_t addr
= ufoPop();
5221 if (count
& (1u<<31)) ufoFatal("invalid error message");
5222 if (count
== 0) ufoFatal("some error");
5223 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
5224 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5225 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
5227 ufoErrMsgBuf
[count
] = 0;
5228 ufoFatal("%s", ufoErrMsgBuf
);
5231 // ////////////////////////////////////////////////////////////////////////// //
5235 static char ufoFNameBuf
[4096];
5238 //==========================================================================
5240 // ufoScanIncludeFileName
5242 // `*psys` and `*psoft` must be initialised!
5244 //==========================================================================
5245 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
5246 uint32_t *psys
, uint32_t *psoft
)
5250 ufo_assert(dest
!= NULL
);
5251 ufo_assert(destsz
> 0);
5253 while (count
!= 0) {
5254 ch
= ufoImgGetU8Ext(addr
);
5256 //if (system) ufoFatal("invalid file name (duplicate system mark)");
5258 } else if (ch
== '?') {
5259 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
5265 addr
+= 1; count
-= 1;
5266 ch
= ufoImgGetU8Ext(addr
);
5267 } while (ch
<= 32 && count
!= 0);
5270 if (count
== 0) ufoFatal("empty include file name");
5271 if (count
>= destsz
) ufoFatal("include file name too long");
5274 while (count
!= 0) {
5275 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
5276 addr
+= 1; count
-= 1;
5282 // (INCLUDE-LINE-FOFS)
5284 UFWORD(PAR_INCLUDE_LINE_FOFS
) {
5285 ufoPush((uint32_t)(int32_t)ufoCurrIncludeLineFileOfs
);
5288 // (INCLUDE-LINE-SEEK)
5290 UFWORD(PAR_INCLUDE_LINE_SEEK
) {
5291 uint32_t fofs
= ufoPop();
5292 uint32_t lidx
= ufoPop();
5293 if (lidx
>= 0x0fffffffU
) lidx
= 0;
5294 if (ufoInFile
== NULL
) ufoFatal("cannot seek without opened include file");
5295 if (fseek(ufoInFile
, (long)fofs
, SEEK_SET
) != 0) {
5296 ufoFatal("error seeking in include file");
5298 ufoInFileLine
= lidx
;
5303 // return number of items in include stack
5304 UFWORD(PAR_INCLUDE_DEPTH
) {
5305 ufoPush(ufoFileStackPos
);
5308 // (INCLUDE-FILE-ID)
5309 // ( isp -- id ) -- isp 0 is current, then 1, etc.
5310 // each include file has unique non-zero id.
5311 UFWORD(PAR_INCLUDE_FILE_ID
) {
5312 const uint32_t isp
= ufoPop();
5315 } else if (isp
<= ufoFileStackPos
) {
5316 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5319 ufoFatal("invalid include stack index");
5323 // (INCLUDE-FILE-LINE)
5325 UFWORD(PAR_INCLUDE_FILE_LINE
) {
5326 const uint32_t isp
= ufoPop();
5328 ufoPush(ufoInFileLine
);
5329 } else if (isp
<= ufoFileStackPos
) {
5330 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5331 ufoPush(stk
->fline
);
5333 ufoFatal("invalid include stack index");
5337 // (INCLUDE-FILE-NAME)
5338 // ( isp -- addr count )
5339 // current file name; at PAD
5340 UFWORD(PAR_INCLUDE_FILE_NAME
) {
5341 const uint32_t isp
= ufoPop();
5342 const char *fname
= NULL
;
5344 fname
= ufoInFileName
;
5345 } else if (isp
<= ufoFileStackPos
) {
5346 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5349 ufoFatal("invalid include stack index");
5352 uint32_t addr
= ufoPop();
5354 if (fname
!= NULL
) {
5355 while (fname
[count
] != 0) {
5356 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
5360 ufoImgPutU8Ext(addr
+ count
, 0);
5366 // (INCLUDE-BUILD-NAME)
5367 // ( addr count soft? system? -- addr count )
5369 UFWORD(PAR_INCLUDE_BUILD_NAME
) {
5370 uint32_t system
= ufoPop();
5371 uint32_t softinclude
= ufoPop();
5372 uint32_t count
= ufoPop();
5373 uint32_t addr
= ufoPop();
5375 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5377 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
5378 &system
, &softinclude
);
5380 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5381 addr
= UFO_PAD_ADDR
+ 4u;
5383 while (ffn
[count
] != 0) {
5384 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)ffn
)[count
]);
5388 ufoImgPutU8Ext(addr
+ count
, 0);
5389 ufoImgPutU32(addr
- 4u, count
);
5394 // (INCLUDE-NO-REFILL)
5395 // ( addr count soft? system? -- )
5396 UFWORD(PAR_INCLUDE_NO_REFILL
) {
5397 uint32_t system
= ufoPop();
5398 uint32_t softinclude
= ufoPop();
5399 uint32_t count
= ufoPop();
5400 uint32_t addr
= ufoPop();
5402 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
5404 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5406 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
5407 &system
, &softinclude
);
5409 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5411 FILE *fl
= fopen(ffn
, "rb");
5413 FILE *fl
= fopen(ffn
, "r");
5416 if (softinclude
) { free(ffn
); return; }
5417 ufoFatal("include file '%s' not found", ffn
);
5419 #ifdef UFO_DEBUG_INCLUDE
5420 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
5425 ufoSetInFileNameReuse(ffn
);
5426 ufoFileId
= ufoLastUsedFileId
;
5427 setLastIncPath(ufoInFileName
, system
);
5431 // ( addr count soft? system? -- )
5432 UFWORD(PAR_INCLUDE
) {
5433 UFCALL(PAR_INCLUDE_NO_REFILL
);
5434 // trigger next line loading
5436 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
5440 UFWORD(DLR_INCLUDE_IMM
) {
5441 int soft
= 0, system
= 0;
5442 // parse include filename
5443 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5444 uint8_t ch
= ufoTibPeekCh();
5446 ufoTibSkipCh(); // skip quote
5448 } else if (ch
== '<') {
5449 ufoTibSkipCh(); // skip quote
5453 ufoFatal("expected quoted string");
5456 if (!ufoPop()) ufoFatal("file name expected");
5457 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5458 if (ufoTibPeekCh() != 0) {
5459 ufoFatal("$INCLUDE doesn't accept extra args yet");
5461 // ( addr count soft? system? -- )
5462 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
5466 //==========================================================================
5468 // ufoCreateFileGuard
5470 //==========================================================================
5471 static const char *ufoCreateFileGuard (const char *fname
) {
5472 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
5473 char *rp
= ufoRealPath(fname
);
5474 if (rp
== NULL
) return NULL
;
5476 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
5478 // hash the buffer; extract file name; create string with path len, file name, and hash
5479 const size_t orgplen
= strlen(rp
);
5480 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
5481 size_t plen
= orgplen
;
5482 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
5483 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5484 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
5485 return ufoRealPathHashBuf
;
5489 // $INCLUDE-ONCE "str"
5490 // includes file only once; unreliable on shitdoze, i believe
5491 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
5492 uint32_t softinclude
= 0, system
= 0;
5493 // parse include filename
5494 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5495 uint8_t ch
= ufoTibPeekCh();
5497 ufoTibSkipCh(); // skip quote
5499 } else if (ch
== '<') {
5500 ufoTibSkipCh(); // skip quote
5504 ufoFatal("expected quoted string");
5507 if (!ufoPop()) ufoFatal("file name expected");
5508 const uint32_t count
= ufoPop();
5509 const uint32_t addr
= ufoPop();
5510 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5511 if (ufoTibPeekCh() != 0) {
5512 ufoFatal("$REQUIRE doesn't accept extra args yet");
5514 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5515 &system
, &softinclude
);
5516 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5517 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
5518 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5519 // this will overwrite `ufoRealPathHashBuf`
5520 const char *guard
= ufoCreateFileGuard(incfname
);
5522 if (guard
== NULL
) {
5523 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
5527 fprintf(stderr
, "GUARD: <%s>\n", guard
);
5529 // now check for the guard
5530 const uint32_t glen
= (uint32_t)strlen(guard
);
5531 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
5532 UForthCondDefine
*dd
;
5533 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5534 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
5535 // nothing to do: already included
5540 dd
= calloc(1, sizeof(UForthCondDefine
));
5541 if (dd
== NULL
) ufoFatal("out of memory for defines");
5542 dd
->name
= calloc(1, glen
+ 1u);
5543 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5544 strcpy(dd
->name
, guard
);
5547 dd
->next
= ufoCondDefines
;
5548 ufoCondDefines
= dd
;
5549 // ( addr count soft? system? -- )
5550 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
5551 UFCALL(PAR_INCLUDE
);
5555 // ////////////////////////////////////////////////////////////////////////// //
5561 UFWORD(PAR_NEW_HANDLE
) {
5562 const uint32_t typeid = ufoPop();
5563 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5564 UfoHandle
*hh
= ufoAllocHandle(typeid);
5565 ufoPush(hh
->ufoHandle
);
5570 UFWORD(PAR_FREE_HANDLE
) {
5571 const uint32_t hx
= ufoPop();
5573 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
5574 UfoHandle
*hh
= ufoGetHandle(hx
);
5575 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
5582 UFWORD(PAR_HANDLE_GET_TYPEID
) {
5583 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");
5587 ufoPush(hh
->typeid);
5592 UFWORD(PAR_HANDLE_SET_TYPEID
) {
5593 const uint32_t hx
= ufoPop();
5594 const uint32_t typeid = ufoPop();
5595 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5596 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5597 UfoHandle
*hh
= ufoGetHandle(hx
);
5598 if (hh
== NULL
) ufoFatal("invalid handle");
5599 hh
->typeid = typeid;
5604 UFWORD(PAR_HANDLE_GET_SIZE
) {
5605 const uint32_t hx
= ufoPop();
5607 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5608 UfoHandle
*hh
= ufoGetHandle(hx
);
5609 if (hh
== NULL
) ufoFatal("invalid handle");
5618 UFWORD(PAR_HANDLE_SET_SIZE
) {
5619 const uint32_t hx
= ufoPop();
5620 const uint32_t size
= ufoPop();
5621 if (size
> 0x04000000) ufoFatal("invalid handle size");
5622 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5623 UfoHandle
*hh
= ufoGetHandle(hx
);
5624 if (hh
== NULL
) ufoFatal("invalid handle");
5625 if (hh
->size
!= size
) {
5630 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
5631 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
5633 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
5636 if (hh
->used
> size
) hh
->used
= size
;
5642 UFWORD(PAR_HANDLE_GET_USED
) {
5643 const uint32_t hx
= ufoPop();
5645 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5646 UfoHandle
*hh
= ufoGetHandle(hx
);
5647 if (hh
== NULL
) ufoFatal("invalid handle");
5656 UFWORD(PAR_HANDLE_SET_USED
) {
5657 const uint32_t hx
= ufoPop();
5658 const uint32_t used
= ufoPop();
5659 if (used
> 0x04000000) ufoFatal("invalid handle used");
5660 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5661 UfoHandle
*hh
= ufoGetHandle(hx
);
5662 if (hh
== NULL
) ufoFatal("invalid handle");
5663 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
5667 #define POP_PREPARE_HANDLE() \
5668 const uint32_t hx = ufoPop(); \
5669 uint32_t idx = ufoPop(); \
5670 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5671 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5672 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5673 UfoHandle *hh = ufoGetHandle(hx); \
5674 if (hh == NULL) ufoFatal("invalid handle")
5677 // ( idx hx -- value )
5678 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5679 POP_PREPARE_HANDLE();
5680 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5681 ufoPush(hh
->data
[idx
]);
5685 // ( idx hx -- value )
5686 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5687 POP_PREPARE_HANDLE();
5688 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5689 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5691 #ifdef UFO_FAST_MEM_ACCESS
5692 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5694 uint32_t res
= hh
->data
[idx
];
5695 res
|= hh
->data
[idx
+ 1u] << 8;
5701 // ( idx hx -- value )
5702 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5703 POP_PREPARE_HANDLE();
5704 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5705 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5707 #ifdef UFO_FAST_MEM_ACCESS
5708 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5710 uint32_t res
= hh
->data
[idx
];
5711 res
|= hh
->data
[idx
+ 1u] << 8;
5712 res
|= hh
->data
[idx
+ 2u] << 16;
5713 res
|= hh
->data
[idx
+ 3u] << 24;
5719 // ( value idx hx -- value )
5720 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5721 POP_PREPARE_HANDLE();
5722 const uint32_t value
= ufoPop();
5723 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5724 hh
->data
[idx
] = value
;
5728 // ( value idx hx -- )
5729 UFWORD(PAR_HANDLE_STORE_WORD
) {
5730 POP_PREPARE_HANDLE();
5731 const uint32_t value
= ufoPop();
5732 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5733 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5735 #ifdef UFO_FAST_MEM_ACCESS
5736 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5738 hh
->data
[idx
] = (uint8_t)value
;
5739 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5744 // ( value idx hx -- )
5745 UFWORD(PAR_HANDLE_STORE_CELL
) {
5746 POP_PREPARE_HANDLE();
5747 const uint32_t value
= ufoPop();
5748 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5749 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5751 #ifdef UFO_FAST_MEM_ACCESS
5752 *(uint32_t *)(hh
->data
+ idx
) = value
;
5754 hh
->data
[idx
] = (uint8_t)value
;
5755 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5756 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5757 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5763 // ( addr count -- stx / FALSE )
5764 UFWORD(PAR_HANDLE_LOAD_FILE
) {
5765 uint32_t count
= ufoPop();
5766 uint32_t addr
= ufoPop();
5768 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5770 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
5771 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
5772 uint8_t ch
= ufoImgGetU8Ext(addr
);
5774 dest
+= 1u; addr
+= 1u; count
-= 1u;
5776 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
5779 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
5781 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
5783 FILE *fl
= fopen(ffn
, "rb");
5785 FILE *fl
= fopen(ffn
, "r");
5793 if (fseek(fl
, 0, SEEK_END
) != 0) {
5795 ufoFatal("seek error in file '%s'", ffn
);
5798 long sz
= ftell(fl
);
5799 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
5801 ufoFatal("tell error in file '%s' (or too big)", ffn
);
5804 if (fseek(fl
, 0, SEEK_SET
) != 0) {
5806 ufoFatal("seek error in file '%s'", ffn
);
5809 UfoHandle
*hh
= ufoAllocHandle(0);
5811 hh
->data
= malloc((uint32_t)sz
);
5812 if (hh
->data
== NULL
) {
5814 ufoFatal("out of memory for file '%s'", ffn
);
5816 hh
->size
= (uint32_t)sz
;
5817 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
5819 ufoFatal("error reading file '%s'", ffn
);
5825 ufoPush(hh
->ufoHandle
);
5829 // ////////////////////////////////////////////////////////////////////////// //
5833 // DEBUG:(DECOMPILE-CFA)
5835 UFWORD(DEBUG_DECOMPILE_CFA
) {
5836 const uint32_t cfa
= ufoPop();
5838 ufoDecompileWord(cfa
);
5841 // DEBUG:(DECOMPILE-MEM)
5842 // ( addr-start addr-end -- )
5843 UFWORD(DEBUG_DECOMPILE_MEM
) {
5844 const uint32_t end
= ufoPop();
5845 const uint32_t start
= ufoPop();
5847 ufoDecompilePart(start
, end
, 0);
5853 ufoPush((uint32_t)ufo_get_msecs());
5856 // this is called by INTERPRET when it is out of input stream
5857 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
5863 UFWORD(MT_NEW_STATE
) {
5864 UfoState
*st
= ufoNewState();
5865 ufoInitStateUserVars(st
, ufoPop());
5871 UFWORD(MT_FREE_STATE
) {
5872 UfoState
*st
= ufoFindState(ufoPop());
5873 if (st
== NULL
) ufoFatal("cannot free unknown state");
5874 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5878 // MTASK:STATE-NAME@
5879 // ( stid -- addr count )
5881 UFWORD(MT_GET_STATE_NAME
) {
5882 UfoState
*st
= ufoFindState(ufoPop());
5883 if (st
== NULL
) ufoFatal("unknown state");
5885 uint32_t addr
= ufoPop();
5887 while (st
->name
[count
] != 0) {
5888 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5891 ufoImgPutU8Ext(addr
+ count
, 0);
5896 // MTASK:STATE-NAME!
5897 // ( addr count stid -- )
5898 UFWORD(MT_SET_STATE_NAME
) {
5899 UfoState
*st
= ufoFindState(ufoPop());
5900 if (st
== NULL
) ufoFatal("unknown state");
5901 uint32_t count
= ufoPop();
5902 uint32_t addr
= ufoPop();
5903 if ((count
& ((uint32_t)1 << 31)) == 0) {
5904 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5905 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5906 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5908 st
->name
[count
] = 0;
5912 // MTASK:STATE-FIRST
5914 UFWORD(MT_STATE_FIRST
) {
5916 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5917 // there should be at least one allocated state
5918 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5919 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5921 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5926 // ( stid -- stid / 0 )
5927 UFWORD(MT_STATE_NEXT
) {
5928 uint32_t stid
= ufoPop();
5929 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5930 // it is already incremented for us, yay!
5931 uint32_t fidx
= stid
/ 32u;
5932 uint8_t fofs
= stid
& 0x1f;
5933 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5934 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5936 while (fofs
!= 32u) {
5937 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5940 ufoPush(fidx
* 32u + fofs
+ 1u);
5944 fidx
+= 1u; fofs
= 0;
5952 // ( ... argc stid -- )
5953 UFWORD(MT_YIELD_TO
) {
5954 UfoState
*st
= ufoFindState(ufoPop());
5955 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5956 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5957 const uint32_t argc
= ufoPop();
5958 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
5959 UfoState
*curst
= ufoCurrState
;
5960 if (st
!= ufoCurrState
) {
5961 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
5962 ufoCurrState
= curst
;
5963 const uint32_t n
= ufoPop();
5967 ufoCurrState
= curst
; // we need to use API call to switch states
5969 ufoSwitchToState(st
); // always use API call for this!
5974 // MTASK:SET-SELF-AS-DEBUGGER
5976 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
5977 ufoDebuggerState
= ufoCurrState
;
5982 // debugger task receives debugge stid on the data stack, and -1 as argc.
5983 // i.e. debugger stask is: ( -1 old-stid )
5984 UFWORD(MT_DEBUGGER_BP
) {
5985 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
&& ufoIsGoodTTY()) {
5986 UfoState
*st
= ufoCurrState
;
5987 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
5992 UFCALL(UFO_BACKTRACE
);
5996 // MTASK:DEBUGGER-RESUME
5998 UFWORD(MT_RESUME_DEBUGEE
) {
5999 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
6000 UfoState
*st
= ufoFindState(ufoPop());
6001 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
6002 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
6003 ufoSwitchToState(st
); // always use API call for this!
6007 // MTASK:DEBUGGER-SINGLE-STEP
6009 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
6010 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
6011 UfoState
*st
= ufoFindState(ufoPop());
6012 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
6013 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
6014 ufoSwitchToState(st
); // always use API call for this!
6015 ufoSingleStep
= 2; // it will be decremented after returning from this word
6020 UFWORD(MT_STATE_IP_GET
) {
6021 UfoState
*st
= ufoFindState(ufoPop());
6022 if (st
== NULL
) ufoFatal("unknown state");
6028 UFWORD(MT_STATE_IP_SET
) {
6029 UfoState
*st
= ufoFindState(ufoPop());
6030 if (st
== NULL
) ufoFatal("unknown state");
6036 UFWORD(MT_STATE_REGA_GET
) {
6037 UfoState
*st
= ufoFindState(ufoPop());
6038 if (st
== NULL
) ufoFatal("unknown state");
6044 UFWORD(MT_STATE_REGA_SET
) {
6045 UfoState
*st
= ufoFindState(ufoPop());
6046 if (st
== NULL
) ufoFatal("unknown state");
6047 st
->regA
= ufoPop();
6050 // MTASK:STATE-USER@
6051 // ( addr stid -- value )
6052 UFWORD(MT_STATE_USER_GET
) {
6053 UfoState
*st
= ufoFindState(ufoPop());
6054 if (st
== NULL
) ufoFatal("unknown state");
6055 const uint32_t addr
= ufoPop();
6056 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
6057 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
6060 ufoFatal("invalid user area address");
6064 // MTASK:STATE-USER!
6065 // ( value addr stid -- )
6066 UFWORD(MT_STATE_USER_SET
) {
6067 UfoState
*st
= ufoFindState(ufoPop());
6068 if (st
== NULL
) ufoFatal("unknown state");
6069 const uint32_t addr
= ufoPop();
6070 const uint32_t value
= ufoPop();
6071 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
6072 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
6074 ufoFatal("invalid user area address");
6078 // MTASK:STATE-RPOPCFA@
6080 UFWORD(MT_STATE_RPOPCFA_GET
) {
6081 UfoState
*st
= ufoFindState(ufoPop());
6082 if (st
== NULL
) ufoFatal("unknown state");
6083 ufoPush(st
->vmRPopCFA
);
6086 // MTASK:STATE-RPOPCFA!
6088 UFWORD(MT_STATE_RPOPCFA_SET
) {
6089 UfoState
*st
= ufoFindState(ufoPop());
6090 if (st
== NULL
) ufoFatal("unknown state");
6091 st
->vmRPopCFA
= ufoPop();
6094 // MTASK:ACTIVE-STATE
6096 UFWORD(MT_ACTIVE_STATE
) {
6097 ufoPush(ufoCurrState
->id
);
6100 // MTASK:YIELDED-FROM
6102 UFWORD(MT_YIELDED_FROM
) {
6103 if (ufoYieldedState
!= NULL
) {
6104 ufoPush(ufoYieldedState
->id
);
6111 // ( stid -- depth )
6112 UFWORD(MT_DSTACK_DEPTH_GET
) {
6113 UfoState
*st
= ufoFindState(ufoPop());
6114 if (st
== NULL
) ufoFatal("unknown state");
6119 // ( stid -- depth )
6120 UFWORD(MT_RSTACK_DEPTH_GET
) {
6121 UfoState
*st
= ufoFindState(ufoPop());
6122 if (st
== NULL
) ufoFatal("unknown state");
6123 ufoPush(st
->RP
- st
->RPTop
);
6129 UfoState
*st
= ufoFindState(ufoPop());
6130 if (st
== NULL
) ufoFatal("unknown state");
6136 UFWORD(MT_LBP_GET
) {
6137 UfoState
*st
= ufoFindState(ufoPop());
6138 if (st
== NULL
) ufoFatal("unknown state");
6143 // ( depth stid -- )
6144 UFWORD(MT_DSTACK_DEPTH_SET
) {
6145 UfoState
*st
= ufoFindState(ufoPop());
6146 if (st
== NULL
) ufoFatal("unknown state");
6147 const uint32_t idx
= ufoPop();
6148 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
6153 // ( depth stid -- )
6154 UFWORD(MT_RSTACK_DEPTH_SET
) {
6155 UfoState
*st
= ufoFindState(ufoPop());
6156 if (st
== NULL
) ufoFatal("unknown state");
6157 const uint32_t idx
= ufoPop();
6158 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
6159 if (idx
>= left
) ufoFatal("invalid rstack index %u (%u)", idx
, left
);
6160 st
->RP
= st
->RPTop
+ idx
;
6166 UfoState
*st
= ufoFindState(ufoPop());
6167 if (st
== NULL
) ufoFatal("unknown state");
6173 UFWORD(MT_LBP_SET
) {
6174 UfoState
*st
= ufoFindState(ufoPop());
6175 if (st
== NULL
) ufoFatal("unknown state");
6180 // ( idx stid -- value )
6181 UFWORD(MT_DSTACK_LOAD
) {
6182 UfoState
*st
= ufoFindState(ufoPop());
6183 if (st
== NULL
) ufoFatal("unknown state");
6184 const uint32_t idx
= ufoPop();
6185 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6186 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
6190 // ( idx stid -- value )
6191 UFWORD(MT_RSTACK_LOAD
) {
6192 UfoState
*st
= ufoFindState(ufoPop());
6193 if (st
== NULL
) ufoFatal("unknown state");
6194 const uint32_t idx
= ufoPop();
6195 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6196 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
6200 // ( idx stid -- value )
6201 UFWORD(MT_LSTACK_LOAD
) {
6202 UfoState
*st
= ufoFindState(ufoPop());
6203 if (st
== NULL
) ufoFatal("unknown state");
6204 const uint32_t idx
= ufoPop();
6205 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
6206 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
6210 // ( value idx stid -- )
6211 UFWORD(MT_DSTACK_STORE
) {
6212 UfoState
*st
= ufoFindState(ufoPop());
6213 if (st
== NULL
) ufoFatal("unknown state");
6214 const uint32_t idx
= ufoPop();
6215 const uint32_t value
= ufoPop();
6216 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6217 st
->dStack
[st
->SP
- idx
- 1u] = value
;
6221 // ( value idx stid -- )
6222 UFWORD(MT_RSTACK_STORE
) {
6223 UfoState
*st
= ufoFindState(ufoPop());
6224 if (st
== NULL
) ufoFatal("unknown state");
6225 const uint32_t idx
= ufoPop();
6226 const uint32_t value
= ufoPop();
6227 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6228 st
->dStack
[st
->RP
- idx
- 1u] = value
;
6232 // ( value idx stid -- )
6233 UFWORD(MT_LSTACK_STORE
) {
6234 UfoState
*st
= ufoFindState(ufoPop());
6235 if (st
== NULL
) ufoFatal("unknown state");
6236 const uint32_t idx
= ufoPop();
6237 const uint32_t value
= ufoPop();
6238 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
6239 st
->dStack
[st
->LP
- idx
- 1u] = value
;
6244 UFWORD(MT_VSP_GET
) {
6245 UfoState
*st
= ufoFindState(ufoPop());
6246 if (st
== NULL
) ufoFatal("unknown state");
6252 UFWORD(MT_VSP_SET
) {
6253 UfoState
*st
= ufoFindState(ufoPop());
6254 if (st
== NULL
) ufoFatal("unknown state");
6255 const uint32_t vsp
= ufoPop();
6256 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6260 // MTASK:STATE-VSP-AT@
6261 // ( idx stidf -- value )
6262 UFWORD(MT_VSP_LOAD
) {
6263 UfoState
*st
= ufoFindState(ufoPop());
6264 if (st
== NULL
) ufoFatal("unknown state");
6265 const uint32_t vsp
= ufoPop();
6266 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6267 ufoPush(st
->vocStack
[vsp
]);
6270 // MTASK:STATE-VSP-AT!
6271 // ( value idx stid -- )
6272 UFWORD(MT_VSP_STORE
) {
6273 UfoState
*st
= ufoFindState(ufoPop());
6274 if (st
== NULL
) ufoFatal("unknown state");
6275 const uint32_t vsp
= ufoPop();
6276 const uint32_t value
= ufoPop();
6277 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6278 st
->vocStack
[vsp
] = value
;
6282 #include "urforth_tty.c"
6285 // ////////////////////////////////////////////////////////////////////////// //
6289 static unsigned char ufoFileIOBuffer
[4096];
6292 //==========================================================================
6296 //==========================================================================
6297 static char *ufoPopFileName (void) {
6298 uint32_t count
= ufoPop();
6299 uint32_t addr
= ufoPop();
6301 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid file name");
6302 if (count
== 0) ufoFatal("empty file name");
6303 if (count
> (uint32_t)sizeof(ufoFNameBuf
) - 1u) ufoFatal("file name too long");
6305 unsigned char *dest
= (unsigned char *)ufoFNameBuf
;
6306 while (count
!= 0) {
6307 *dest
= ufoImgGetU8Ext(addr
);
6308 dest
+= 1u; addr
+= 1u; count
-= 1u;
6317 UFWORD(FILES_ERRNO
) {
6318 ufoPush((uint32_t)errno
);
6322 // ( addr count -- success? )
6323 UFWORD(FILES_UNLINK
) {
6324 const char *fname
= ufoPopFileName();
6325 ufoPushBool(unlink(fname
) == 0);
6329 // ( addr count -- handle TRUE / FALSE )
6330 UFWORD(FILES_OPEN_RO
) {
6331 const char *fname
= ufoPopFileName();
6332 const int fd
= open(fname
, O_RDONLY
);
6334 ufoPush((uint32_t)fd
);
6342 // ( addr count -- handle TRUE / FALSE )
6343 UFWORD(FILES_OPEN_RW
) {
6344 const char *fname
= ufoPopFileName();
6345 const int fd
= open(fname
, O_RDWR
);
6347 ufoPush((uint32_t)fd
);
6355 // ( addr count -- handle TRUE / FALSE )
6356 UFWORD(FILES_CREATE
) {
6357 const char *fname
= ufoPopFileName();
6358 //FIXME: add variable with default flags
6359 const int fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6361 ufoPush((uint32_t)fd
);
6369 // ( handle -- success? )
6370 UFWORD(FILES_CLOSE
) {
6371 const int32_t fd
= (int32_t)ufoPop();
6372 if (fd
< 0) ufoFatal("invalid file handle in 'CLOSE'");
6373 ufoPushBool(close(fd
) == 0);
6377 // ( handle -- ofs TRUE / FALSE )
6378 // `handle` cannot be 0.
6379 UFWORD(FILES_TELL
) {
6380 const int32_t fd
= (int32_t)ufoPop();
6381 if (fd
< 0) ufoFatal("invalid file handle in 'TELL'");
6382 const off_t pos
= lseek(fd
, 0, SEEK_CUR
);
6383 if (pos
!= (off_t
)-1) {
6384 ufoPush((uint32_t)pos
);
6392 // ( ofs whence handle -- TRUE / FALSE )
6393 // `handle` cannot be 0.
6394 UFWORD(FILES_SEEK_EX
) {
6395 const int32_t fd
= (int32_t)ufoPop();
6396 const uint32_t whence
= ufoPop();
6397 const uint32_t ofs
= ufoPop();
6398 if (fd
< 0) ufoFatal("invalid file handle in 'SEEK-EX'");
6399 if (whence
!= (uint32_t)SEEK_SET
&&
6400 whence
!= (uint32_t)SEEK_CUR
&&
6401 whence
!= (uint32_t)SEEK_END
) ufoFatal("invalid `whence` in 'SEEK-EX'");
6402 const off_t pos
= lseek(fd
, (off_t
)ofs
, (int)whence
);
6403 ufoPushBool(pos
!= (off_t
)-1);
6407 // ( handle -- size TRUE / FALSE )
6408 // `handle` cannot be 0.
6409 UFWORD(FILES_SIZE
) {
6410 const int32_t fd
= (int32_t)ufoPop();
6411 if (fd
< 0) ufoFatal("invalid file handle in 'SIZE'");
6412 const off_t origpos
= lseek(fd
, 0, SEEK_CUR
);
6413 if (origpos
== (off_t
)-1) {
6416 const off_t size
= lseek(fd
, 0, SEEK_END
);
6417 if (size
== (off_t
)-1) {
6418 (void)lseek(origpos
, 0, SEEK_SET
);
6420 } else if (lseek(origpos
, 0, SEEK_SET
) == origpos
) {
6421 ufoPush((uint32_t)size
);
6430 // ( addr count handle -- rdsize TRUE / FALSE )
6431 // `handle` cannot be 0.
6432 UFWORD(FILES_READ
) {
6433 const int32_t fd
= (int32_t)ufoPop();
6434 if (fd
< 0) ufoFatal("invalid file handle in 'READ'");
6435 uint32_t count
= ufoPop();
6436 uint32_t addr
= ufoPop();
6439 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6440 while (count
!= done
) {
6441 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6442 if (rd
> count
) rd
= count
;
6444 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6445 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6446 if (errno
== EINTR
) continue;
6447 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6454 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6455 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6465 // ( addr count handle -- TRUE / FALSE )
6466 // `handle` cannot be 0.
6467 UFWORD(FILES_READ_EXACT
) {
6468 const int32_t fd
= (int32_t)ufoPop();
6469 if (fd
< 0) ufoFatal("invalid file handle in 'READ-EXACT'");
6470 uint32_t count
= ufoPop();
6471 uint32_t addr
= ufoPop();
6473 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6474 while (count
!= 0) {
6475 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6476 if (rd
> count
) rd
= count
;
6478 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6479 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6480 if (errno
== EINTR
) continue;
6481 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6486 if (rd
== 0) { ufoPushBool(0); return; } // still error
6488 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6489 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6498 // ( addr count handle -- TRUE / FALSE )
6499 // `handle` cannot be 0.
6500 UFWORD(FILES_WRITE
) {
6501 const int32_t fd
= (int32_t)ufoPop();
6502 if (fd
< 0) ufoFatal("invalid file handle in 'WRITE'");
6503 uint32_t count
= ufoPop();
6504 uint32_t addr
= ufoPop();
6506 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to write to file");
6507 while (count
!= 0) {
6508 uint32_t wr
= (uint32_t)sizeof(ufoFileIOBuffer
);
6509 if (wr
> count
) wr
= count
;
6510 for (uint32_t f
= 0; f
!= wr
; f
+= 1u) {
6511 ufoFileIOBuffer
[f
] = ufoImgGetU8Ext(addr
+ f
);
6514 const ssize_t xres
= write(fd
, ufoFileIOBuffer
, wr
);
6515 if (xres
>= 0) { wr
= (uint32_t)xres
; break; }
6516 if (errno
== EINTR
) continue;
6517 fprintf(stderr
, "ERRNO: %d (fd=%d)\n", errno
, fd
);
6518 //if (errno == EAGAIN || errno == EWOULDBLOCK) { wr = 0; break; }
6523 if (wr
== 0) { ufoPushBool(1); return; } // still error
6524 count
-= wr
; addr
+= wr
;
6531 // ////////////////////////////////////////////////////////////////////////// //
6535 //==========================================================================
6539 // create a new state, its execution will start from the given CFA.
6540 // state is not automatically activated.
6542 //==========================================================================
6543 static UfoState
*ufoNewState (void) {
6544 // find free state id
6546 uint32_t bmp
= ufoStateUsedBitmap
[0];
6547 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
6549 bmp
= ufoStateUsedBitmap
[fidx
];
6551 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
6552 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6554 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
6555 ufo_assert(fidx
< UFO_MAX_STATES
);
6556 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
6557 ufo_assert(ufoStateMap
[fidx
] == NULL
);
6558 UfoState
*st
= calloc(1, sizeof(UfoState
));
6559 if (st
== NULL
) ufoFatal("out of memory for states");
6561 ufoStateMap
[fidx
] = st
;
6562 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
6563 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6568 //==========================================================================
6572 // free all memory used for the state, remove it from state list.
6573 // WARNING! never free current state!
6575 //==========================================================================
6576 static void ufoFreeState (UfoState
*st
) {
6578 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
6579 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
6580 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
6581 const uint32_t fidx
= st
->id
- 1u;
6582 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6583 ufo_assert(fidx
< UFO_MAX_STATES
);
6584 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
6585 ufo_assert(ufoStateMap
[fidx
] == st
);
6586 // free default TIB handle
6587 UfoState
*oldst
= ufoCurrState
;
6589 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
6590 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
6591 UfoHandle
*tibh
= ufoGetHandle(tib
);
6592 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
6594 ufoCurrState
= oldst
;
6596 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
6598 ufoStateMap
[fidx
] = NULL
;
6599 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
6604 //==========================================================================
6608 //==========================================================================
6609 static UfoState
*ufoFindState (uint32_t stid
) {
6610 UfoState
*res
= NULL
;
6611 if (stid
>= 0 && stid
<= UFO_MAX_STATES
) {
6614 ufo_assert(ufoCurrState
!= NULL
);
6615 stid
= ufoCurrState
->id
- 1u;
6619 res
= ufoStateMap
[stid
];
6621 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
6622 ufo_assert(res
->id
== stid
+ 1u);
6624 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
6631 //==========================================================================
6635 //==========================================================================
6636 static void ufoSwitchToState (UfoState
*newst
) {
6637 ufo_assert(newst
!= NULL
);
6638 if (newst
!= ufoCurrState
) {
6639 ufoCurrState
= newst
;
6644 // ////////////////////////////////////////////////////////////////////////// //
6645 // initial dictionary definitions
6650 #define UFWORD(name_) do { \
6651 const uint32_t xcfa_ = ufoCFAsUsed; \
6652 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6653 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6655 ufoDefineNative(""#name_, xcfa_, 0); \
6658 #define UFWORDX(strname_,name_) do { \
6659 const uint32_t xcfa_ = ufoCFAsUsed; \
6660 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6661 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6663 ufoDefineNative(strname_, xcfa_, 0); \
6666 #define UFWORD_IMM(name_) do { \
6667 const uint32_t xcfa_ = ufoCFAsUsed; \
6668 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6669 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6671 ufoDefineNative(""#name_, xcfa_, 1); \
6674 #define UFWORDX_IMM(strname_,name_) do { \
6675 const uint32_t xcfa_ = ufoCFAsUsed; \
6676 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6677 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6679 ufoDefineNative(strname_, xcfa_, 1); \
6682 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
6685 //==========================================================================
6687 // ufoFindWordChecked
6689 //==========================================================================
6690 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
6691 const uint32_t cfa
= ufoFindWord(wname
);
6692 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
6697 //==========================================================================
6701 // get "FORTH" vocid
6703 //==========================================================================
6704 uint32_t ufoGetForthVocId (void) {
6705 return ufoForthVocId
;
6709 //==========================================================================
6711 // ufoVocSetOnlyDefs
6713 //==========================================================================
6714 void ufoVocSetOnlyDefs (uint32_t vocid
) {
6715 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6716 ufoImgPutU32(ufoAddrContext
, vocid
);
6720 //==========================================================================
6724 // return voc PFA (vocid)
6726 //==========================================================================
6727 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
6728 // create wordlist struct
6729 // typeid, used by Forth code (structs and such)
6730 ufoImgEmitU32(0); // typeid
6731 // vocid points here, to "LATEST-LFA"
6732 const uint32_t vocid
= UFO_GET_DP();
6733 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
6734 ufoImgEmitU32(0); // latest
6735 const uint32_t vlink
= UFO_GET_DP();
6736 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
6737 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
6738 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
6743 ufoImgEmitU32(parentvocid
); // parent
6744 const uint32_t hdraddr
= UFO_GET_DP();
6745 ufoImgEmitU32(0); // word header
6746 // create empty hash table
6747 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
6748 // update CONTEXT and CURRENT if this is the first wordlist ever
6749 if (ufoImgGetU32(ufoAddrContext
) == 0) {
6750 ufoImgPutU32(ufoAddrContext
, vocid
);
6752 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
6753 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6755 // create word header
6756 if (wname
!= NULL
&& wname
[0] != 0) {
6758 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6760 //UFW_FLAG_IMMEDIATE|
6762 //UFW_FLAG_NORETURN|
6768 flags |= UFW_FLAG_VOCAB;
6770 flags
&= 0xffffff00u
;
6771 flags
|= UFW_FLAG_VOCAB
;
6772 ufoCreateWordHeader(wname
, flags
);
6773 const uint32_t cfa
= UFO_GET_DP();
6774 ufoImgEmitU32(ufoDoVocCFA
); // cfa
6775 ufoImgEmitU32(vocid
); // pfa
6776 // update vocab header pointer
6777 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
6778 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
6779 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6780 ufoDumpWordHeader(lfa
);
6787 //==========================================================================
6791 //==========================================================================
6792 static void ufoSetLatestArgs (uint32_t warg
) {
6793 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
6794 const uint32_t lfa
= ufoImgGetU32(curr
);
6795 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
6796 uint32_t flags
= ufoImgGetU32(nfa
);
6797 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
6798 flags
&= ~UFW_WARG_MASK
;
6799 flags
|= warg
& UFW_WARG_MASK
;
6800 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
6801 ufoImgPutU32(nfa
, flags
);
6802 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6803 ufoDumpWordHeader(lfa
);
6808 //==========================================================================
6812 //==========================================================================
6813 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
6814 cfaidx
|= UFO_ADDR_CFA_BIT
;
6815 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6817 //UFW_FLAG_IMMEDIATE|
6819 //UFW_FLAG_NORETURN|
6825 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
6826 ufoCreateWordHeader(wname
, flags
);
6827 ufoImgEmitU32(cfaidx
);
6831 //==========================================================================
6833 // ufoDefineConstant
6835 //==========================================================================
6836 static void ufoDefineConstant (const char *name
, uint32_t value
) {
6837 ufoDefineNative(name
, ufoDoConstCFA
, 0);
6838 ufoImgEmitU32(value
);
6842 //==========================================================================
6846 //==========================================================================
6847 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
6848 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
6849 ufoImgEmitU32(addr
);
6853 //==========================================================================
6857 //==========================================================================
6859 static void ufoDefineVar (const char *name, uint32_t value) {
6860 ufoDefineNative(name, ufoDoVarCFA, 0);
6861 ufoImgEmitU32(value);
6866 //==========================================================================
6870 //==========================================================================
6872 static void ufoDefineDefer (const char *name, uint32_t value) {
6873 ufoDefineNative(name, ufoDoDeferCFA, 0);
6874 ufoImgEmitU32(value);
6879 //==========================================================================
6883 //==========================================================================
6884 static void ufoHiddenWords (void) {
6885 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6886 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6890 //==========================================================================
6894 //==========================================================================
6895 static void ufoPublicWords (void) {
6896 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6897 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
6901 //==========================================================================
6905 //==========================================================================
6907 static void ufoDefineForth (const char *name) {
6908 ufoDefineNative(name, ufoDoForthCFA, 0);
6913 //==========================================================================
6915 // ufoDefineForthImm
6917 //==========================================================================
6919 static void ufoDefineForthImm (const char *name) {
6920 ufoDefineNative(name, ufoDoForthCFA, 1);
6925 //==========================================================================
6927 // ufoDefineForthHidden
6929 //==========================================================================
6931 static void ufoDefineForthHidden (const char *name) {
6932 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6933 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6934 ufoDefineNative(name, ufoDoForthCFA, 0);
6935 ufoImgPutU32(ufoAddrNewWordFlags, flags);
6940 //==========================================================================
6942 // ufoDefineSColonForth
6944 // create word suitable for scattered colon extension
6946 //==========================================================================
6947 static void ufoDefineSColonForth (const char *name
) {
6948 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6949 // placeholder for scattered colon
6950 // it will compile two branches:
6951 // the first branch will jump to the first "..:" word (or over the two branches)
6952 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
6953 // this way, each extension word will simply fix the last branch address, and update list tail
6954 // at the creation time, second branch points to the first branch
6955 UFC("FORTH:(BRANCH)");
6956 const uint32_t xjmp
= UFO_GET_DP();
6958 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
6959 ufoImgPutU32(xjmp
, UFO_GET_DP());
6963 //==========================================================================
6967 //==========================================================================
6968 UFO_FORCE_INLINE
void ufoDoneForth (void) {
6969 UFC("FORTH:(EXIT)");
6973 //==========================================================================
6977 // compile string literal, the same as QUOTE_IMM
6979 //==========================================================================
6980 static void ufoCompileStrLitEx (const char *str
, const uint32_t slen
) {
6981 if (str
== NULL
) str
= "";
6982 if (slen
> 255) ufoFatal("string literal too long");
6983 UFC("FORTH:(LITSTR8)");
6984 ufoImgEmitU8((uint8_t)slen
);
6985 for (size_t f
= 0; f
< slen
; f
+= 1) {
6986 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
6993 //==========================================================================
6997 //==========================================================================
6999 static void ufoCompileStrLit (const char *str) {
7000 ufoCompileStrLitEx(str, (uint32_t)strlen(str));
7005 //==========================================================================
7009 //==========================================================================
7010 static void ufoCompileLit (uint32_t value
) {
7012 ufoImgEmitU32(value
);
7016 //==========================================================================
7020 //==========================================================================
7022 static void ufoCompileCFALit (const char *wname) {
7023 UFC("FORTH:(LITCFA)");
7024 const uint32_t cfa = ufoFindWordChecked(wname);
7030 //==========================================================================
7034 //==========================================================================
7035 static int ufoXStrEquCI (const char *word
, const char *text
, uint32_t tlen
) {
7036 while (tlen
!= 0 && *word
) {
7037 if (toUpper(*word
) != toUpper(*text
)) return 0;
7038 word
+= 1u; text
+= 1u; tlen
-= 1u;
7040 return (tlen
== 0 && *word
== 0);
7044 #define UFO_MAX_LABEL_NAME (63)
7045 typedef struct UfoLabel_t
{
7048 char name
[UFO_MAX_LABEL_NAME
];
7049 uint32_t addr
; // jump chain tail, or address
7051 uint32_t word
; // is this a forward word definition?
7052 struct UfoLabel_t
*next
;
7055 static UfoLabel
*ufoLabels
= NULL
;
7058 //==========================================================================
7060 // ufoFindAddLabelEx
7062 //==========================================================================
7063 static UfoLabel
*ufoFindAddLabelEx (const char *name
, uint32_t namelen
, int allowAdd
) {
7064 if (namelen
== 0 || namelen
> UFO_MAX_LABEL_NAME
) ufoFatal("invalid label name");
7065 const uint32_t hash
= joaatHashBufCI(name
, namelen
);
7066 UfoLabel
*lbl
= ufoLabels
;
7067 while (lbl
!= NULL
) {
7068 if (lbl
->hash
== hash
&& lbl
->namelen
== namelen
) {
7071 while (ok
&& sidx
!= namelen
) {
7072 ok
= (toUpper(name
[sidx
]) == toUpper(lbl
->name
[sidx
]));
7081 lbl
= calloc(1, sizeof(UfoLabel
));
7083 lbl
->namelen
= namelen
;
7084 memcpy(lbl
->name
, name
, namelen
);
7085 lbl
->name
[namelen
] = 0;
7086 lbl
->next
= ufoLabels
;
7095 //==========================================================================
7099 //==========================================================================
7100 static UfoLabel
*ufoFindAddLabel (const char *name
, uint32_t namelen
) {
7101 return ufoFindAddLabelEx(name
, namelen
, 1);
7105 //==========================================================================
7109 //==========================================================================
7110 static UfoLabel
*ufoFindLabel (const char *name
, uint32_t namelen
) {
7111 return ufoFindAddLabelEx(name
, namelen
, 0);
7115 //==========================================================================
7117 // ufoTrySimpleNumber
7119 // only decimal and C-like hexes; with an optional sign
7121 //==========================================================================
7122 static int ufoTrySimpleNumber (const char *text
, uint32_t tlen
, uint32_t *num
) {
7125 if (tlen
!= 0 && *text
== '+') { text
+= 1u; tlen
-= 1u; }
7126 else if (tlen
!= 0 && *text
== '-') { neg
= 1; text
+= 1u; tlen
-= 1u; }
7128 int base
= 10; // default base
7129 if (tlen
> 2 && text
[0] == '0' && toUpper(text
[1]) == 'X') {
7132 text
+= 2u; tlen
-= 2u;
7135 if (tlen
== 0 || digitInBase(*text
, base
) < 0) return 0;
7142 if (!wasDigit
) return 0;
7145 dig
= digitInBase(*text
, base
);
7146 if (dig
< 0) return 0;
7148 n
= n
* (uint32_t)base
+ (uint32_t)dig
;
7150 text
+= 1u; tlen
-= 1u;
7153 if (!wasDigit
) return 0;
7154 if (neg
) n
= ~n
+ 1u;
7160 //==========================================================================
7162 // ufoEmitLabelChain
7164 //==========================================================================
7165 static void ufoEmitLabelChain (UfoLabel
*lbl
) {
7166 ufo_assert(lbl
!= NULL
);
7167 ufo_assert(lbl
->defined
== 0);
7168 const uint32_t here
= UFO_GET_DP();
7169 ufoImgEmitU32(lbl
->addr
);
7174 //==========================================================================
7176 // ufoFixLabelChainHere
7178 //==========================================================================
7179 static void ufoFixLabelChainHere (UfoLabel
*lbl
) {
7180 ufo_assert(lbl
!= NULL
);
7181 ufo_assert(lbl
->defined
== 0);
7182 const uint32_t here
= UFO_GET_DP();
7183 while (lbl
->addr
!= 0) {
7184 const uint32_t aprev
= ufoImgGetU32(lbl
->addr
);
7185 ufoImgPutU32(lbl
->addr
, here
);
7193 #define UFO_MII_WORD_COMPILE_IMM (-4)
7194 #define UFO_MII_WORD_CFA_LIT (-3)
7195 #define UFO_MII_WORD_COMPILE (-2)
7196 #define UFO_MII_IN_WORD (-1)
7197 #define UFO_MII_NO_WORD (0)
7198 #define UFO_MII_WORD_NAME (1)
7199 #define UFO_MII_WORD_NAME_IMM (2)
7200 #define UFO_MII_WORD_NAME_HIDDEN (3)
7202 static int ufoMinInterpState
= UFO_MII_NO_WORD
;
7205 //==========================================================================
7207 // ufoFinalLabelCheck
7209 //==========================================================================
7210 static void ufoFinalLabelCheck (void) {
7212 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) {
7213 ufoFatal("missing semicolon");
7215 while (ufoLabels
!= NULL
) {
7216 UfoLabel
*lbl
= ufoLabels
; ufoLabels
= lbl
->next
;
7217 if (!lbl
->defined
) {
7218 fprintf(stderr
, "UFO ERROR: label '%s' is not defined!\n", lbl
->name
);
7223 if (errorCount
!= 0) {
7224 ufoFatal("%d undefined label%s", errorCount
, (errorCount
!= 1 ? "s" : ""));
7229 //==========================================================================
7233 // this is so i could write Forth definitions more easily
7236 // $name -- reference
7237 // $name: -- definition
7239 //==========================================================================
7240 UFO_DISABLE_INLINE
void ufoInterpretLine (const char *line
) {
7241 char wname
[UFO_MAX_WORD_LENGTH
];
7242 uint32_t wlen
, num
, cfa
;
7245 if (*(const unsigned char *)line
<= 32) {
7247 } else if (ufoMinInterpState
== UFO_MII_WORD_CFA_LIT
||
7248 ufoMinInterpState
== UFO_MII_WORD_COMPILE
||
7249 ufoMinInterpState
== UFO_MII_WORD_COMPILE_IMM
)
7251 // "[']"/"COMPILE"/"[COMPILE]" argument
7253 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7254 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7255 memcpy(wname
, line
, wlen
);
7257 switch (ufoMinInterpState
) {
7258 case UFO_MII_WORD_CFA_LIT
: UFC("FORTH:(LITCFA)"); break;
7259 case UFO_MII_WORD_COMPILE
: UFC("FORTH:(LITCFA)"); break;
7260 case UFO_MII_WORD_COMPILE_IMM
: break;
7261 default: ufo_assert(0);
7263 cfa
= ufoFindWord(wname
);
7267 // forward reference
7268 lbl
= ufoFindAddLabel(line
, wlen
);
7269 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7270 ufoFatal("unknown word: '%s'", wname
);
7273 ufoEmitLabelChain(lbl
);
7275 switch (ufoMinInterpState
) {
7276 case UFO_MII_WORD_CFA_LIT
: break;
7277 case UFO_MII_WORD_COMPILE
: UFC("FORTH:COMPILE,"); break;
7278 case UFO_MII_WORD_COMPILE_IMM
: break;
7279 default: ufo_assert(0);
7281 ufoMinInterpState
= UFO_MII_IN_WORD
;
7283 } else if (ufoMinInterpState
> UFO_MII_NO_WORD
) {
7286 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7287 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7288 if (wlen
> 2 && line
[0] == ':' && line
[wlen
- 1u] == ':') ufoFatal("invalid word name");
7289 memcpy(wname
, line
, wlen
);
7291 const uint32_t oldFlags
= ufoImgGetU32(ufoAddrNewWordFlags
);
7292 if (ufoMinInterpState
== UFO_MII_WORD_NAME_HIDDEN
) {
7293 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
| UFW_FLAG_HIDDEN
);
7295 ufoDefineNative(wname
, ufoDoForthCFA
, (ufoMinInterpState
== UFO_MII_WORD_NAME_IMM
));
7296 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
);
7297 ufoMinInterpState
= UFO_MII_IN_WORD
;
7298 // check for forward references
7299 lbl
= ufoFindLabel(line
, wlen
);
7301 if (lbl
->defined
|| !lbl
->word
) {
7302 ufoFatal("label/word conflict for '%.*s'", (unsigned)wlen
, line
);
7304 ufoFixLabelChainHere(lbl
);
7307 } else if ((line
[0] == ';' && line
[1] == ';') ||
7308 (line
[0] == '-' && line
[1] == '-') ||
7309 (line
[0] == '/' && line
[1] == '/') ||
7310 (line
[0] == '\\' && ((const unsigned char *)line
)[1] <= 32))
7312 ufoFatal("do not use single-line comments");
7313 } else if (line
[0] == '(' && ((const unsigned char *)line
)[1] <= 32) {
7314 while (*line
&& *line
!= ')') line
+= 1;
7315 if (*line
== ')') line
+= 1;
7319 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7320 if (wlen
== 1 && (line
[0] == '"' || line
[0] == '`')) {
7322 const char qch
= line
[0];
7323 if (!line
[1]) ufoFatal("unterminated string literal");
7324 // skip quote and space
7325 if (((const unsigned char *)line
)[1] <= 32) line
+= 2u; else line
+= 1u;
7327 while (line
[wlen
] && line
[wlen
] != qch
) wlen
+= 1u;
7328 if (line
[wlen
] != qch
) ufoFatal("unterminated string literal");
7329 ufoCompileStrLitEx(line
, wlen
);
7330 line
+= wlen
+ 1u; // skip final quote
7331 } else if (wlen
== 1 && line
[0] == ':') {
7333 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7334 ufoMinInterpState
= UFO_MII_WORD_NAME
;
7336 } else if (wlen
== 1 && line
[0] == ';') {
7338 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected semicolon");
7339 ufoImgEmitU32(ufoFindWordChecked("FORTH:(EXIT)"));
7340 ufoMinInterpState
= UFO_MII_NO_WORD
;
7342 } else if (wlen
== 2 && line
[0] == '!' && line
[1] == ':') {
7343 // new immediate word
7344 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7345 ufoMinInterpState
= UFO_MII_WORD_NAME_IMM
;
7347 } else if (wlen
== 2 && line
[0] == '*' && line
[1] == ':') {
7349 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7350 ufoMinInterpState
= UFO_MII_WORD_NAME_HIDDEN
;
7352 } else if (wlen
== 3 && memcmp(line
, "[']", 3) == 0) {
7354 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7355 ufoMinInterpState
= UFO_MII_WORD_CFA_LIT
;
7357 } else if (wlen
== 7 && ufoXStrEquCI("COMPILE", line
, wlen
)) {
7359 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7360 ufoMinInterpState
= UFO_MII_WORD_COMPILE
;
7362 } else if (wlen
== 9 && ufoXStrEquCI("[COMPILE]", line
, wlen
)) {
7364 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7365 ufoMinInterpState
= UFO_MII_WORD_COMPILE_IMM
;
7369 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7370 memcpy(wname
, line
, wlen
);
7372 cfa
= ufoFindWord(wname
);
7376 } else if (ufoTrySimpleNumber(line
, wlen
, &num
)) {
7377 // compile numeric literal
7380 // unknown word, this may be a forward reference, or a label definition
7381 // label defintion starts with "$"
7382 // (there are no words starting with "$" in the initial image)
7383 if (line
[0] == '$') {
7384 if (wlen
== 1) ufoFatal("dollar what?");
7385 if (wlen
> 2 && line
[wlen
- 1u] == ':') {
7387 lbl
= ufoFindAddLabel(line
, wlen
- 1u);
7388 if (lbl
->defined
) ufoFatal("double label '%s' definition", lbl
->name
);
7389 ufoFixLabelChainHere(lbl
);
7392 lbl
= ufoFindAddLabel(line
, wlen
);
7394 ufoImgEmitU32(lbl
->addr
);
7396 ufoEmitLabelChain(lbl
);
7400 // forward reference
7401 lbl
= ufoFindAddLabel(line
, wlen
);
7402 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7403 ufoFatal("unknown word: '%s'", wname
);
7406 ufoEmitLabelChain(lbl
);
7416 //==========================================================================
7420 //==========================================================================
7421 UFO_DISABLE_INLINE
void ufoReset (void) {
7422 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
7424 ufoSP
= 0; ufoRP
= 0;
7425 ufoLP
= 0; ufoLBP
= 0;
7428 ufoVMStop
= 0; ufoVMAbort
= 0;
7433 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
7434 const uint32_t tibDef
= ufoImgGetU32(ufoAddrDefTIB
);
7435 ufoInitStateUserVars(ufoCurrState
, 0);
7437 ufoImgPutU32(ufoAddrTIBx
, tib
);
7438 ufoImgPutU32(ufoAddrDefTIB
, tibDef
);
7439 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
7442 ufoImgPutU32(ufoAddrDPTemp
, 0);
7444 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
7445 ufoVocSetOnlyDefs(ufoForthVocId
);
7449 //==========================================================================
7451 // ufoDefineEmitType
7453 //==========================================================================
7454 UFO_DISABLE_INLINE
void ufoDefineEmitType (void) {
7457 ufoInterpretLine(": EMIT ( ch -- ) (NORM-EMIT-CHAR) (EMIT) ;");
7461 ufoInterpretLine(": XEMIT ( ch -- ) (NORM-XEMIT-CHAR) (EMIT) ;");
7465 ufoInterpretLine(": CR ( -- ) NL (EMIT) ;");
7471 " LASTCR? FORTH:(TBRANCH) $endcr-exit CR "
7474 //ufoDecompileWord(ufoFindWordChecked("ENDCR"));
7478 ufoInterpretLine(": SPACE ( -- ) BL (EMIT) ;");
7483 ": SPACES ( count -- ) "
7485 " DUP 0> FORTH:(0BRANCH) $spaces-exit "
7487 " FORTH:(BRANCH) $spaces-again "
7493 // ( addr count -- )
7495 ": TYPE ( addr count -- ) "
7498 " DUP 0> FORTH:(0BRANCH) $type-exit "
7501 " FORTH:(BRANCH) $type-again "
7507 // ( addr count -- )
7509 ": XTYPE ( addr count -- ) "
7512 " DUP 0> FORTH:(0BRANCH) $xtype-exit "
7515 " FORTH:(BRANCH) $xtype-again "
7523 ": HERE ( -- here ) "
7524 " FORTH:(DP-TEMP) @ ?DUP "
7525 " FORTH:(TBRANCH) $here-exit "
7533 ": ALIGN-HERE ( -- ) "
7534 "$align-here-loop: "
7536 " FORTH:(0BRANCH) $align-here-exit "
7538 " FORTH:(BRANCH) $align-here-loop "
7539 "$align-here-exit: "
7543 // ( C:addr count -- ) ( E: -- addr count )
7545 ": STRLITERAL ( C:addr count -- ) ( E: -- addr count ) "
7546 " DUP 255 U> ` string literal too long` ?ERROR "
7547 " STATE @ FORTH:(0BRANCH) $strlit-exit "
7549 " ['] FORTH:(LITSTR8) COMPILE, "
7551 " ( compile length ) "
7553 " ( compile chars ) "
7555 " DUP 0<> FORTH:(0BRANCH) $strlit-loop-exit "
7557 " FORTH:(BRANCH) $strlit-loop "
7558 "$strlit-loop-exit: "
7560 " ( final 0: our counter is 0 here, so use it ) "
7566 // ( -- addr count )
7568 "!: \" ( -- addr count ) "
7569 " 34 PARSE ` string literal expected` ?NOT-ERROR "
7570 " COMPILER:(UNESCAPE) STRLITERAL "
7575 //==========================================================================
7577 // ufoDefineInterpret
7579 // define "INTERPRET" in Forth
7581 //==========================================================================
7582 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
7583 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
7585 // return "stop flag"
7587 "*: (UFO-INTERPRET-NEXT-LINE) ( -- continue? ) "
7588 " STATE @ FORTH:(TBRANCH) $ipn_incomp "
7589 " ( interpreter allowed to cross include boundary ) "
7590 " REFILL FORTH:(BRANCH) $ipn_done "
7592 " ( compiler is not allowed to cross include boundary ) "
7593 " REFILL-NOCROSS ` compiler cannot cross file boundaries` ?NOT-ERROR "
7598 ufoInterpNextLineCFA
= ufoFindWordChecked("FORTH:(UFO-INTERPRET-NEXT-LINE)");
7599 ufoInterpretLine("*: (INTERPRET-NEXT-LINE) (USER-INTERPRET-NEXT-LINE) @ EXECUTE-TAIL ;");
7601 // skip comments, parse name, refilling lines if necessary
7602 // returning FALSE as counter means: "no addr, exit INTERPRET"
7604 "*: (INTERPRET-PARSE-NAME) ( -- addr count / FALSE ) "
7605 "$label_ipn_again: "
7606 " TRUE (PARSE-SKIP-COMMENTS) PARSE-NAME "
7607 " DUP FORTH:(TBRANCH) $label_ipn_exit_fwd "
7608 " 2DROP (INTERPRET-NEXT-LINE) "
7609 " FORTH:(TBRANCH) $label_ipn_again "
7611 "$label_ipn_exit_fwd: "
7613 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
7618 " FORTH:(INTERPRET-PARSE-NAME) ( addr count / FALSE )"
7619 " ?DUP FORTH:(0BRANCH) $interp-done "
7620 " ( try defered checker ) "
7621 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7622 " FALSE (INTERPRET-CHECK-WORD) FORTH:(TBRANCH) $interp-again "
7623 " 2DUP FIND-WORD ( addr count cfa TRUE / addr count FALSE ) "
7624 " FORTH:(0BRANCH) $interp-try-number "
7626 " NROT 2DROP ( drop word string ) "
7627 " STATE @ FORTH:(0BRANCH) $interp-exec "
7628 " ( compiling; check immediate bit ) "
7629 " DUP CFA->NFA @ COMPILER:(WFLAG-IMMEDIATE) AND FORTH:(TBRANCH) $interp-exec "
7631 " FORTH:COMPILE, FORTH:(BRANCH) $interp-again "
7634 " EXECUTE FORTH:(BRANCH) $interp-again "
7635 " ( not a word, try a number ) "
7636 "$interp-try-number: "
7637 " 2DUP TRUE BASE @ (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE ) "
7638 " FORTH:(0BRANCH) $interp-number-error "
7640 " NROT 2DROP ( drop word string ) "
7641 " ( do we need to compile it? ) "
7642 " STATE @ FORTH:(0BRANCH) $interp-again "
7643 " COMPILE FORTH:(LIT) FORTH:, "
7644 " FORTH:(BRANCH) $interp-again "
7646 "$interp-number-error: "
7647 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7648 " FALSE (INTERPRET-WORD-NOT-FOUND) FORTH:(TBRANCH) $interp-again "
7649 " ENDCR SPACE XTYPE ` -- wut?` TYPE CR "
7650 " ` unknown word` ERROR "
7653 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
7657 //==========================================================================
7661 //==========================================================================
7662 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
7663 uint32_t imgAddr
= 0;
7665 // reserve 32 bytes for nothing
7666 for (uint32_t f
= 0; f
< 32; f
+= 1) {
7667 ufoImgPutU8(imgAddr
, 0);
7671 while ((imgAddr
& 3) != 0) {
7672 ufoImgPutU8(imgAddr
, 0);
7677 ufoAddrDP
= imgAddr
;
7678 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7681 ufoAddrDPTemp
= imgAddr
;
7682 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7685 ufoAddrLastXFA
= imgAddr
;
7686 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7689 ufoAddrVocLink
= imgAddr
;
7690 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7693 ufoAddrNewWordFlags
= imgAddr
;
7694 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
7696 // WORD-REDEFINE-WARN-MODE
7697 ufoAddrRedefineWarning
= imgAddr
;
7698 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
7700 // setup (DP) and (DP-TEMP)
7701 ufoImgPutU32(ufoAddrDP
, imgAddr
);
7702 ufoImgPutU32(ufoAddrDPTemp
, 0);
7705 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
7710 //==========================================================================
7712 // ufoInitStateUserVars
7714 //==========================================================================
7715 static void ufoInitStateUserVars (UfoState
*st
, uint32_t cfa
) {
7716 ufo_assert(st
!= NULL
);
7717 if (st
->imageTempSize
< 8192u) {
7718 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
7719 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
7720 st
->imageTemp
= itmp
;
7721 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
7722 st
->imageTempSize
= 8192;
7724 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
7725 st
->imageTemp
[(ufoAddrSTATE
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7726 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
7727 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7728 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7729 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7730 st
->imageTemp
[(ufoAddrContext
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7731 st
->imageTemp
[(ufoAddrCurrent
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7732 st
->imageTemp
[(ufoAddrSelf
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7733 st
->imageTemp
[(ufoAddrInterNextLine
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoInterpNextLineCFA
;
7734 st
->imageTemp
[(ufoAddrEP
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7735 // init other things, because this procedure is used in `ufoReset()` too
7736 st
->SP
= 0; st
->RP
= 0; st
->RPTop
= 0; st
->regA
= 0;
7737 st
->LP
= 0; st
->LBP
= 0; st
->vmRPopCFA
= 0;
7742 st
->rStack
[0] = 0xdeadf00d; // dummy value
7743 st
->rStack
[1] = cfa
;
7749 //==========================================================================
7751 // ufoInitBasicWords
7753 //==========================================================================
7754 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
7755 ufoDefineConstant("FALSE", 0);
7756 ufoDefineConstant("TRUE", ufoTrueValue
);
7758 ufoDefineConstant("BL", 32);
7759 ufoDefineConstant("NL", 10);
7762 ufoDefineUserVar("BASE", ufoAddrBASE
);
7763 ufoDefineUserVar("TIB", ufoAddrTIBx
);
7764 ufoDefineUserVar(">IN", ufoAddrINx
);
7765 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
7766 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
7767 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
7768 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
7769 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
7770 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
7772 ufoDefineUserVar("STATE", ufoAddrSTATE
);
7773 ufoDefineConstant("CONTEXT", ufoAddrContext
);
7774 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
7775 ufoDefineConstant("(SELF)", ufoAddrSelf
); // used in OOP implementations
7776 ufoDefineConstant("(USER-INTERPRET-NEXT-LINE)", ufoAddrInterNextLine
);
7777 ufoDefineConstant("(EXC-FRAME-PTR)", ufoAddrEP
);
7780 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
7781 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
7782 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
7783 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
7784 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
7785 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
7786 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
7788 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
7789 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
7790 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
7792 ufoDefineConstant("(DP)", ufoAddrDP
);
7793 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
7796 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
7797 UFWORDX("SP0!", SP0_STORE
);
7798 UFWORDX("RP0!", RP0_STORE
);
7800 UFWORDX("PAD", PAD
);
7803 UFWORDX("C@", CPEEK
);
7804 UFWORDX("W@", WPEEK
);
7807 UFWORDX("C!", CPOKE
);
7808 UFWORDX("W!", WPOKE
);
7810 UFWORDX(",", COMMA
);
7811 UFWORDX("C,", CCOMMA
);
7812 UFWORDX("W,", WCOMMA
);
7814 UFWORDX("A>", REGA_LOAD
);
7815 UFWORDX(">A", REGA_STORE
);
7816 UFWORDX("A-SWAP", REGA_SWAP
);
7817 UFWORDX("+1>A", REGA_INC
);
7818 UFWORDX("+4>A", REGA_INC_CELL
);
7819 UFWORDX("A>R", REGA_TO_R
);
7820 UFWORDX("R>A", R_TO_REGA
);
7822 UFWORDX("@A+", PEEK_REGA_IDX
);
7823 UFWORDX("C@A+", CPEEK_REGA_IDX
);
7824 UFWORDX("W@A+", WPEEK_REGA_IDX
);
7826 UFWORDX("!A+", POKE_REGA_IDX
);
7827 UFWORDX("C!A+", CPOKE_REGA_IDX
);
7828 UFWORDX("W!A+", WPOKE_REGA_IDX
);
7831 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
7832 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
7833 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
7834 UFWORDX("(LITSTR8)", PAR_LITSTR8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
7835 UFWORDX("(EXIT)", PAR_EXIT
);
7837 ufoLitStr8CFA
= ufoFindWordChecked("FORTH:(LITSTR8)");
7839 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
7840 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
7841 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
7842 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
7844 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7845 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7846 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7847 UFWORDX("(+0BRANCH)", PAR_P0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7848 UFWORDX("(+BRANCH)", PAR_PBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7849 UFWORDX("(-0BRANCH)", PAR_M0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7850 UFWORDX("(-BRANCH)", PAR_MBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7851 UFWORDX("(DATASKIP)", PAR_DATASKIP
); ufoSetLatestArgs(UFW_WARG_DATASKIP
);
7856 //==========================================================================
7858 // ufoInitBasicCompilerWords
7860 //==========================================================================
7861 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
7862 // create "COMPILER" vocabulary
7863 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
7864 ufoVocSetOnlyDefs(ufoCompilerVocId
);
7866 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
7867 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
7868 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
7869 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
7870 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
7871 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
7872 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
7873 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
7875 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
7876 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
7877 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
7878 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
7879 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
7880 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
7881 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
7882 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
7884 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
7885 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
7886 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
7887 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
7888 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
7889 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
7890 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
7891 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
7892 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
7894 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
7895 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
7896 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
7897 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
7898 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
7899 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
7900 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
7902 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
7903 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
7904 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
7905 ufoDefineConstant("(REDEFINE-WARN-PARENTS)", UFO_REDEF_WARN_PARENTS
);
7907 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
7909 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
7913 " FORTH:STATE FORTH:@ ` expecting interpretation mode` FORTH:?ERROR "
7918 " FORTH:STATE FORTH:@ ` expecting compilation mode` FORTH:?NOT-ERROR "
7921 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
7922 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
7924 ufoVocSetOnlyDefs(ufoForthVocId
);
7927 ufoInterpretLine("!: [ COMPILER:?COMP 0 STATE ! ;");
7929 ufoInterpretLine(": ] COMPILER:?EXEC 1 STATE ! ;");
7933 //==========================================================================
7937 //==========================================================================
7938 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
7939 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
7941 UFWORDX("CFA->PFA", CFA2PFA
);
7942 UFWORDX("CFA->NFA", CFA2NFA
);
7943 UFWORDX("CFA->LFA", CFA2LFA
);
7944 UFWORDX("CFA->WEND", CFA2WEND
);
7946 UFWORDX("PFA->CFA", PFA2CFA
);
7947 UFWORDX("PFA->NFA", PFA2NFA
);
7949 UFWORDX("NFA->CFA", NFA2CFA
);
7950 UFWORDX("NFA->PFA", NFA2PFA
);
7951 UFWORDX("NFA->LFA", NFA2LFA
);
7953 UFWORDX("LFA->CFA", LFA2CFA
);
7954 UFWORDX("LFA->PFA", LFA2PFA
);
7955 UFWORDX("LFA->BFA", LFA2BFA
);
7956 UFWORDX("LFA->XFA", LFA2XFA
);
7957 UFWORDX("LFA->YFA", LFA2YFA
);
7958 UFWORDX("LFA->NFA", LFA2NFA
);
7960 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
7961 UFWORDX("FIND-WORD", FIND_WORD
);
7962 UFWORDX("(FIND-WORD-IN-VOC)", FIND_WORD_IN_VOC
);
7963 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", FIND_WORD_IN_VOC_AND_PARENTS
);
7966 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
7969 UFWORDX("?DUP", QDUP
);
7970 UFWORDX("2DUP", DDUP
);
7972 UFWORDX("2DROP", DDROP
);
7974 UFWORDX("2SWAP", DSWAP
);
7976 UFWORDX("2OVER", DOVER
);
7979 UFWORDX("PICK", PICK
);
7980 UFWORDX("ROLL", ROLL
);
7984 UFWORDX(">R", DTOR
);
7985 UFWORDX("R>", RTOD
);
7986 UFWORDX("R@", RPEEK
);
7987 UFWORDX("RPICK", RPICK
);
7988 UFWORDX("RROLL", RROLL
);
7989 UFWORDX("RSWAP", RSWAP
);
7990 UFWORDX("ROVER", ROVER
);
7991 UFWORDX("RROT", RROT
);
7992 UFWORDX("RNROT", RNROT
);
7994 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
7995 UFWORDX("(EMIT)", PAR_EMIT
);
7996 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR
);
7997 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR
);
7998 UFWORDX("LASTCR?", LASTCRQ
);
7999 UFWORDX("LASTCR!", LASTCRSET
);
8003 UFWORDX("-", MINUS
);
8005 UFWORDX("U*", UMUL
);
8007 UFWORDX("U/", UDIV
);
8008 UFWORDX("MOD", MOD
);
8009 UFWORDX("UMOD", UMOD
);
8010 UFWORDX("/MOD", DIVMOD
);
8011 UFWORDX("U/MOD", UDIVMOD
);
8012 UFWORDX("*/", MULDIV
);
8013 UFWORDX("U*/", UMULDIV
);
8014 UFWORDX("*/MOD", MULDIVMOD
);
8015 UFWORDX("U*/MOD", UMULDIVMOD
);
8016 UFWORDX("M*", MMUL
);
8017 UFWORDX("UM*", UMMUL
);
8018 UFWORDX("M/MOD", MDIVMOD
);
8019 UFWORDX("UM/MOD", UMDIVMOD
);
8020 UFWORDX("UDS*", UDSMUL
);
8022 UFWORDX("SM/REM", SMREM
);
8023 UFWORDX("FM/MOD", FMMOD
);
8025 UFWORDX("D-", DMINUS
);
8026 UFWORDX("D+", DPLUS
);
8027 UFWORDX("D=", DEQU
);
8028 UFWORDX("D<", DLESS
);
8029 UFWORDX("D<=", DLESSEQU
);
8030 UFWORDX("DU<", DULESS
);
8031 UFWORDX("DU<=", DULESSEQU
);
8038 UFWORDX(">", GREAT
);
8039 UFWORDX("<=", LESSEQU
);
8040 UFWORDX(">=", GREATEQU
);
8041 UFWORDX("U<", ULESS
);
8042 UFWORDX("U>", UGREAT
);
8043 UFWORDX("U<=", ULESSEQU
);
8044 UFWORDX("U>=", UGREATEQU
);
8046 UFWORDX("<>", NOTEQU
);
8048 UFWORDX("0=", ZERO_EQU
);
8049 UFWORDX("0<>", ZERO_NOTEQU
);
8051 UFWORDX("NOT", ZERO_EQU
);
8052 UFWORDX("NOTNOT", ZERO_NOTEQU
);
8058 UFWORDX("LOGAND", LOGAND
);
8059 UFWORDX("LOGOR", LOGOR
);
8062 UFWORDX("(TIB-IN)", TIB_IN
);
8063 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
8064 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
8065 UFWORDX("TIB-GETCH", TIB_GETCH
);
8066 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
8068 UFWORDX("REFILL", REFILL
);
8069 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
8072 UFWORDX("(PARSE)", PAR_PARSE
);
8073 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
8075 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
8076 UFWORDX("PARSE-NAME", PARSE_NAME
);
8077 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
8078 UFWORDX("PARSE", PARSE
);
8081 UFWORDX("(VSP@)", PAR_GET_VSP
);
8082 UFWORDX("(VSP!)", PAR_SET_VSP
);
8083 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
8084 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
8085 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
8087 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
8088 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
8089 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
8092 UFWORDX("ERROR", ERROR
);
8093 UFWORDX("FATAL-ERROR", ERROR
);
8095 ufoInterpretLine(": 1+ ( n -- n+1 ) 1 + ;");
8096 ufoInterpretLine(": 1- ( n -- n-1 ) 1 - ;");
8097 ufoInterpretLine(": 2+ ( n -- n+2 ) 2 + ;");
8098 ufoInterpretLine(": 2- ( n -- n-2 ) 2 - ;");
8099 ufoInterpretLine(": 4+ ( n -- n+4 ) 4 + ;");
8100 ufoInterpretLine(": 4- ( n -- n-4 ) 4 - ;");
8102 ufoInterpretLine(": 2* ( n -- n*2 ) 1 ASH ;");
8103 ufoInterpretLine(": 2/ ( n -- n/2 ) -1 ASH ;");
8104 ufoInterpretLine(": 4* ( n -- n*4 ) 2 ASH ;");
8105 ufoInterpretLine(": 4/ ( n -- n/4 ) -2 ASH ;");
8107 ufoInterpretLine(": 2U* ( u -- u*2 ) 1 LSH ;");
8108 ufoInterpretLine(": 2U/ ( u -- u/2 ) -1 LSH ;");
8109 ufoInterpretLine(": 4U* ( u -- u*4 ) 2 LSH ;");
8110 ufoInterpretLine(": 4U/ ( u -- u/4 ) -2 LSH ;");
8112 ufoInterpretLine(": 0< ( n -- n<0 ) 0 < ;");
8113 ufoInterpretLine(": 0> ( n -- n>0 ) 0 > ;");
8114 ufoInterpretLine(": 0<= ( n -- n<0 ) 0 <= ;");
8115 ufoInterpretLine(": 0>= ( n -- n>0 ) 0 >= ;");
8117 ufoInterpretLine(": @A ( idx -- v ) 0 @A+ ;");
8118 ufoInterpretLine(": C@A ( idx -- v ) 0 C@A+ ;");
8119 ufoInterpretLine(": W@A ( idx -- v ) 0 W@A+ ;");
8121 ufoInterpretLine(": !A ( idx -- v ) 0 !A+ ;");
8122 ufoInterpretLine(": C!A ( idx -- v ) 0 C!A+ ;");
8123 ufoInterpretLine(": W!A ( idx -- v ) 0 W!A+ ;");
8127 ufoInterpretLine(": ABORT ` \"ABORT\" called` ERROR ;");
8130 // ( errflag addr count -- )
8132 ": ?ERROR ( errflag addr count -- ) "
8133 " ROT FORTH:(0BRANCH) $qerr_skip ERROR "
8139 // ( errflag addr count -- )
8141 ": ?NOT-ERROR ( errflag addr count -- ) "
8142 " ROT FORTH:(TBRANCH) $qnoterr_skip ERROR "
8148 ": FIND-WORD-IN-VOC ( vocid addr count -- cfa TRUE / FALSE ) "
8149 " 0 (FIND-WORD-IN-VOC) ;");
8152 ": FIND-WORD-IN-VOC-AND-PARENTS ( vocid addr count -- cfa TRUE / FALSE ) "
8153 " 0 (FIND-WORD-IN-VOC-AND-PARENTS) ;");
8155 UFWORDX("GET-MSECS", GET_MSECS
);
8159 //==========================================================================
8161 // ufoInitHandleWords
8163 //==========================================================================
8164 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
8165 // create "HANDLE" vocabulary
8166 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
8167 ufoVocSetOnlyDefs(handleVocId
);
8168 UFWORDX("NEW", PAR_NEW_HANDLE
);
8169 UFWORDX("FREE", PAR_FREE_HANDLE
);
8170 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
8171 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
8172 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
8173 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
8174 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
8175 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
8176 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
8177 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
8178 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
8179 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
8180 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
8181 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
8182 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
8183 ufoVocSetOnlyDefs(ufoForthVocId
);
8187 //==========================================================================
8189 // ufoInitHigherWords
8191 //==========================================================================
8192 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
8193 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
8194 UFWORDX("(INCLUDE-BUILD-NAME)", PAR_INCLUDE_BUILD_NAME
);
8195 UFWORDX("(INCLUDE-NO-REFILL)", PAR_INCLUDE_NO_REFILL
);
8196 UFWORDX("(INCLUDE-LINE-SEEK)", PAR_INCLUDE_LINE_SEEK
);
8198 UFWORDX("(INCLUDE-LINE-FOFS)", PAR_INCLUDE_LINE_FOFS
);
8199 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
8200 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
8201 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
8202 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
8204 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
8205 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
8206 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
8208 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
8209 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
8213 //==========================================================================
8215 // ufoInitStringWords
8217 //==========================================================================
8218 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
8219 // create "STRING" vocabulary
8220 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
8221 ufoVocSetOnlyDefs(stringVocId
);
8222 UFWORDX("=", STREQU
);
8223 UFWORDX("=CI", STREQUCI
);
8224 UFWORDX("SEARCH", SEARCH
);
8225 UFWORDX("HASH", STRHASH
);
8226 UFWORDX("HASH-CI", STRHASHCI
);
8227 ufoVocSetOnlyDefs(ufoForthVocId
);
8231 //==========================================================================
8233 // ufoInitDebugWords
8235 //==========================================================================
8236 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
8237 // create "DEBUG" vocabulary
8238 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
8239 ufoVocSetOnlyDefs(debugVocId
);
8240 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
8241 UFWORDX("(DECOMPILE-MEM)", DEBUG_DECOMPILE_MEM
);
8242 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
8243 UFWORDX("DUMP-STACK", DUMP_STACK
);
8244 UFWORDX("BACKTRACE-TASK", UFO_BACKTRACE_TASK
);
8245 UFWORDX("DUMP-STACK-TASK", DUMP_STACK_TASK
);
8246 UFWORDX("DUMP-RSTACK-TASK", DUMP_RSTACK_TASK
);
8247 UFWORDX("(BP)", MT_DEBUGGER_BP
);
8248 UFWORDX("IP->NFA", IP2NFA
);
8249 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
8250 UFWORDX("IP->FILE-HASH/LINE", IP2FILEHASHLINE
);
8251 ufoVocSetOnlyDefs(ufoForthVocId
);
8255 //==========================================================================
8259 //==========================================================================
8260 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
8261 // create "MTASK" vocabulary
8262 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
8263 ufoVocSetOnlyDefs(mtVocId
);
8264 UFWORDX("NEW-STATE", MT_NEW_STATE
);
8265 UFWORDX("FREE-STATE", MT_FREE_STATE
);
8266 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
8267 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
8268 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
8269 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
8270 UFWORDX("YIELD-TO", MT_YIELD_TO
);
8271 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
8272 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
8273 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
8274 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
8275 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
8276 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
8277 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
8278 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
8279 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
8280 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
8281 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
8282 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
8283 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
8284 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
8285 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
8286 UFWORDX("STATE-LP@", MT_LP_GET
);
8287 UFWORDX("STATE-LBP@", MT_LBP_GET
);
8288 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
8289 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
8290 UFWORDX("STATE-LP!", MT_LP_SET
);
8291 UFWORDX("STATE-LBP!", MT_LBP_SET
);
8292 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
8293 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
8294 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
8295 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
8296 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
8297 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
8298 UFWORDX("STATE-VSP@", MT_VSP_GET
);
8299 UFWORDX("STATE-VSP!", MT_VSP_SET
);
8300 UFWORDX("STATE-VSP-AT@", MT_VSP_LOAD
);
8301 UFWORDX("STATE-VSP-AT!", MT_VSP_STORE
);
8302 ufoVocSetOnlyDefs(ufoForthVocId
);
8306 //==========================================================================
8310 //==========================================================================
8311 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
8312 // create "TTY" vocabulary
8313 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
8314 ufoVocSetOnlyDefs(ttyVocId
);
8315 UFWORDX("TTY?", TTY_TTYQ
);
8316 UFWORDX("RAW?", TTY_RAWQ
);
8317 UFWORDX("SIZE", TTY_SIZE
);
8318 UFWORDX("SET-RAW", TTY_SET_RAW
);
8319 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
8320 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
8321 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
8322 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
8323 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
8324 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
8325 ufoVocSetOnlyDefs(ufoForthVocId
);
8329 //==========================================================================
8331 // ufoInitFilesWords
8333 //==========================================================================
8334 UFO_DISABLE_INLINE
void ufoInitFilesWords (void) {
8335 // create "FILES" vocabulary
8336 const uint32_t filesVocId
= ufoCreateVoc("FILES", 0, UFW_FLAG_PROTECTED
);
8337 ufoVocSetOnlyDefs(filesVocId
);
8338 ufoDefineConstant("SEEK-SET", SEEK_SET
);
8339 ufoDefineConstant("SEEK-CUR", SEEK_CUR
);
8340 ufoDefineConstant("SEEK-END", SEEK_END
);
8342 UFWORDX("OPEN-R/O", FILES_OPEN_RO
);
8343 UFWORDX("OPEN-R/W", FILES_OPEN_RW
);
8344 UFWORDX("CREATE", FILES_CREATE
);
8345 UFWORDX("CLOSE", FILES_CLOSE
);
8346 UFWORDX("TELL", FILES_TELL
);
8347 UFWORDX("SEEK-EX", FILES_SEEK_EX
);
8348 UFWORDX("SIZE", FILES_SIZE
);
8349 UFWORDX("READ", FILES_READ
);
8350 UFWORDX("READ-EXACT", FILES_READ_EXACT
);
8351 UFWORDX("WRITE", FILES_WRITE
);
8353 UFWORDX("UNLINK", FILES_UNLINK
);
8355 UFWORDX("ERRNO", FILES_ERRNO
);
8358 ": SEEK ( ofs handle -- success? ) "
8359 " SEEK-SET FORTH:SWAP SEEK-EX "
8364 ": READ-EXACT ( addr count handle -- success? ) "
8365 " FORTH:OVER FORTH:>R ( save count ) "
8366 " READ FORTH:DUP FORTH:(0BRANCH) $files-read-exact-error "
8367 " FORTH:DROP ( drop TRUE ) FORTH:R@ = "
8368 "$files-read-exact-error: "
8373 ufoVocSetOnlyDefs(ufoForthVocId
);
8377 //==========================================================================
8379 // ufoInitVeryVeryHighWords
8381 //==========================================================================
8382 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
8384 //ufoDefineDefer("INTERPRET", idumbCFA);
8386 ufoDefineEmitType();
8388 // ( addr count FALSE -- addr count FALSE / TRUE )
8389 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
8391 // ( addr count FALSE -- addr count FALSE / TRUE )
8392 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
8394 // ( -- ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
8395 ufoDefineSColonForth("(EXIT-EXTENDER)");
8399 ufoInterpretLine("!: EXIT ( -- ) COMPILER:?COMP (EXIT-EXTENDER) COMPILE FORTH:(EXIT) ;");
8401 ufoDefineInterpret();
8403 //ufoDumpVocab(ufoCompilerVocId);
8406 ": RUN-INTERPRET-LOOP "
8407 "$run-interp-loop-again: "
8408 " RP0! INTERPRET (UFO-INTERPRET-FINISHED-ACTION) "
8409 " FORTH:(BRANCH) $run-interp-loop-again "
8413 #define UFO_ADD_DO_CFA(cfx_) do { \
8414 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
8415 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
8420 //==========================================================================
8424 //==========================================================================
8425 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
8427 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
8429 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
8431 // allocate default TIB handle
8432 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
8433 //ufoDefTIB = tibh->ufoHandle;
8435 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
8436 UFO_ADD_DO_CFA(Forth
);
8437 UFO_ADD_DO_CFA(Variable
);
8438 UFO_ADD_DO_CFA(Value
);
8439 UFO_ADD_DO_CFA(Const
);
8440 UFO_ADD_DO_CFA(Defer
);
8441 UFO_ADD_DO_CFA(Voc
);
8442 UFO_ADD_DO_CFA(Create
);
8443 UFO_ADD_DO_CFA(UserVariable
);
8445 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
8449 // create "FORTH" vocabulary (it should be the first one)
8450 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
8451 ufoVocSetOnlyDefs(ufoForthVocId
);
8453 // base low-level interpreter words
8454 ufoInitBasicWords();
8459 // some COMPILER words
8460 ufoInitBasicCompilerWords();
8462 // STRING vocabulary
8463 ufoInitStringWords();
8466 ufoInitDebugWords();
8471 // HANDLE vocabulary
8472 ufoInitHandleWords();
8478 ufoInitFilesWords();
8480 // some higher-level FORTH words (includes, etc.)
8481 ufoInitHigherWords();
8483 // very-very high-level FORTH words
8484 ufoInitVeryVeryHighWords();
8486 ufoFinalLabelCheck();
8489 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
8498 // ////////////////////////////////////////////////////////////////////////// //
8499 // virtual machine executor
8503 //==========================================================================
8507 // address interpreter
8509 //==========================================================================
8510 static void ufoRunVMCFA (uint32_t cfa
) {
8511 const uint32_t oldRPTop
= ufoRPTop
;
8513 #ifdef UFO_TRACE_VM_RUN
8514 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
8520 // VM execution loop
8522 if (ufoVMAbort
) ufoFatal("user abort");
8523 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
8524 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
8525 if (ufoVMRPopCFA
== 0) {
8527 if (ufoIP
== 0) ufoFatal("IP is NULL");
8528 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
8529 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
8531 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
8534 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
8535 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
8536 // get next word CFAIDX, and check it
8537 uint32_t cfaidx
= ufoImgGetU32(cfa
);
8538 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
8539 #ifdef UFO_TRACE_VM_RUN
8540 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
8542 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
8543 fprintf(stderr
, "######################################\n");
8545 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
8546 cfaidx
&= UFO_ADDR_CFA_MASK
;
8547 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
8548 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
8549 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
8551 #ifdef UFO_TRACE_VM_RUN
8552 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
8553 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
8555 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
8557 // if CFA points somewhere inside a dict, this is "DOES>" word
8558 // IP points to PFA we need to push
8559 // CFA points to Forth word we need to jump to
8560 #ifdef UFO_TRACE_VM_DOER
8561 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
8562 UFCALL(UFO_BACKTRACE
);
8564 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
8565 ufoRPush(ufoIP
); // push IP
8566 ufoIP
= cfaidx
; // fix IP
8568 // that's all we need to activate the debugger
8569 if (ufoSingleStep
) {
8571 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
8572 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
8573 UfoState
*ost
= ufoCurrState
;
8574 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
8579 } while (ufoRP
!= oldRPTop
);
8584 // ////////////////////////////////////////////////////////////////////////// //
8588 //==========================================================================
8592 // register new word
8594 //==========================================================================
8595 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
8596 ufo_assert(cfa
!= NULL
);
8597 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8598 uint32_t cfaidx
= ufoCFAsUsed
;
8599 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
8600 ufoForthCFAs
[cfaidx
] = cfa
;
8602 //ufoDefineNative(wname, xcfa, 0);
8603 cfaidx
|= UFO_ADDR_CFA_BIT
;
8604 flags
&= 0xffffff00u
;
8605 ufoCreateWordHeader(wname
, flags
);
8606 const uint32_t res
= UFO_GET_DP();
8607 ufoImgEmitU32(cfaidx
);
8612 //==========================================================================
8614 // ufoRegisterDataWord
8616 //==========================================================================
8617 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
8620 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8621 flags
&= 0xffffff00u
;
8622 ufoCreateWordHeader(wname
, flags
);
8623 ufoImgEmitU32(cfaidx
);
8624 const uint32_t res
= UFO_GET_DP();
8625 ufoImgEmitU32(value
);
8630 //==========================================================================
8632 // ufoRegisterConstant
8634 //==========================================================================
8635 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
8636 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
8640 //==========================================================================
8642 // ufoRegisterVariable
8644 //==========================================================================
8645 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
8646 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
8650 //==========================================================================
8654 //==========================================================================
8655 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
8656 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
8660 //==========================================================================
8664 //==========================================================================
8665 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
8666 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
8670 //==========================================================================
8672 // ufoFindWordInVocabulary
8674 // check if we have the corresponding word.
8675 // return CFA suitable for executing, or 0.
8677 //==========================================================================
8678 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
8679 if (wname
== NULL
|| wname
[0] == 0) return 0;
8680 size_t wlen
= strlen(wname
);
8681 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
8682 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
8686 //==========================================================================
8690 //==========================================================================
8691 uint32_t ufoGetIP (void) {
8696 //==========================================================================
8700 //==========================================================================
8701 void ufoSetIP (uint32_t newip
) {
8706 //==========================================================================
8710 //==========================================================================
8711 int ufoIsExecuting (void) {
8712 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
8716 //==========================================================================
8720 //==========================================================================
8721 int ufoIsCompiling (void) {
8722 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
8726 //==========================================================================
8730 //==========================================================================
8731 void ufoSetExecuting (void) {
8732 ufoImgPutU32(ufoAddrSTATE
, 0);
8736 //==========================================================================
8740 //==========================================================================
8741 void ufoSetCompiling (void) {
8742 ufoImgPutU32(ufoAddrSTATE
, 1);
8746 //==========================================================================
8750 //==========================================================================
8751 uint32_t ufoGetHere () {
8752 return UFO_GET_DP();
8756 //==========================================================================
8760 //==========================================================================
8761 uint32_t ufoGetPad () {
8767 //==========================================================================
8771 //==========================================================================
8772 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
8773 return ufoTibPeekChOfs(ofs
);
8777 //==========================================================================
8781 //==========================================================================
8782 uint8_t ufoTIBGetCh (void) {
8783 return ufoTibGetCh();
8787 //==========================================================================
8791 //==========================================================================
8792 void ufoTIBSkipCh (void) {
8797 //==========================================================================
8803 //==========================================================================
8804 int ufoTIBSRefill (int allowCrossIncludes
) {
8805 return ufoLoadNextLine(allowCrossIncludes
);
8809 //==========================================================================
8813 //==========================================================================
8814 uint32_t ufoPeekData (void) {
8819 //==========================================================================
8823 //==========================================================================
8824 uint32_t ufoPopData (void) {
8829 //==========================================================================
8833 //==========================================================================
8834 void ufoPushData (uint32_t value
) {
8835 return ufoPush(value
);
8839 //==========================================================================
8843 //==========================================================================
8844 void ufoPushBoolData (int val
) {
8849 //==========================================================================
8853 //==========================================================================
8854 uint32_t ufoPeekRet (void) {
8859 //==========================================================================
8863 //==========================================================================
8864 uint32_t ufoPopRet (void) {
8869 //==========================================================================
8873 //==========================================================================
8874 void ufoPushRet (uint32_t value
) {
8875 return ufoRPush(value
);
8879 //==========================================================================
8883 //==========================================================================
8884 void ufoPushBoolRet (int val
) {
8885 ufoRPush(val
? ufoTrueValue
: 0);
8889 //==========================================================================
8893 //==========================================================================
8894 uint8_t ufoPeekByte (uint32_t addr
) {
8895 return ufoImgGetU8Ext(addr
);
8899 //==========================================================================
8903 //==========================================================================
8904 uint16_t ufoPeekWord (uint32_t addr
) {
8911 //==========================================================================
8915 //==========================================================================
8916 uint32_t ufoPeekCell (uint32_t addr
) {
8923 //==========================================================================
8927 //==========================================================================
8928 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
8929 ufoImgPutU8(addr
, value
);
8933 //==========================================================================
8937 //==========================================================================
8938 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
8945 //==========================================================================
8949 //==========================================================================
8950 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
8957 //==========================================================================
8961 //==========================================================================
8962 uint32_t ufoGetPAD (void) {
8963 return UFO_PAD_ADDR
;
8967 //==========================================================================
8971 //==========================================================================
8972 void ufoEmitByte (uint32_t value
) {
8973 ufoImgEmitU8(value
);
8977 //==========================================================================
8981 //==========================================================================
8982 void ufoEmitWord (uint32_t value
) {
8983 ufoImgEmitU8(value
& 0xff);
8984 ufoImgEmitU8((value
>> 8) & 0xff);
8988 //==========================================================================
8992 //==========================================================================
8993 void ufoEmitCell (uint32_t value
) {
8994 ufoImgEmitU32(value
);
8998 //==========================================================================
9002 //==========================================================================
9003 int ufoIsInited (void) {
9004 return (ufoMode
!= UFO_MODE_NONE
);
9008 static void (*ufoUserPostInitCB
) (void);
9011 //==========================================================================
9013 // ufoSetUserPostInit
9015 // called after main initialisation
9017 //==========================================================================
9018 void ufoSetUserPostInit (void (*cb
) (void)) {
9019 ufoUserPostInitCB
= cb
;
9023 //==========================================================================
9027 //==========================================================================
9028 void ufoInit (void) {
9029 if (ufoMode
!= UFO_MODE_NONE
) return;
9030 ufoMode
= UFO_MODE_NATIVE
;
9033 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
9035 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
9037 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
9038 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
9040 ufoCurrState
= ufoNewState();
9041 strcpy(ufoCurrState
->name
, "MAIN");
9042 ufoInitStateUserVars(ufoCurrState
, 0);
9043 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
9044 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
9046 ufoYieldedState
= NULL
;
9047 ufoDebuggerState
= NULL
;
9050 #ifdef UFO_DEBUG_STARTUP_TIMES
9051 uint32_t stt
= ufo_get_msecs();
9052 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
9055 #ifdef UFO_DEBUG_STARTUP_TIMES
9056 uint32_t ett
= ufo_get_msecs();
9057 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
9062 if (ufoUserPostInitCB
) {
9063 ufoUserPostInitCB();
9068 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
9070 FILE *ufl
= fopen(ufmname
, "rb");
9072 FILE *ufl
= fopen(ufmname
, "r");
9076 ufoSetInFileNameReuse(ufmname
);
9078 ufoFileId
= ufoLastUsedFileId
;
9079 setLastIncPath(ufoInFileName
, 1);
9082 ufoFatal("cannot load init code");
9085 if (ufoInFile
!= NULL
) {
9086 ufoRunInterpretLoop();
9091 //==========================================================================
9095 //==========================================================================
9096 void ufoFinishVM (void) {
9101 //==========================================================================
9105 // check if VM was exited due to `ufoFinishVM()`
9107 //==========================================================================
9108 int ufoWasVMFinished (void) {
9109 return (ufoVMStop
!= 0);
9113 //==========================================================================
9117 // ( -- addr count TRUE / FALSE )
9118 // does base TIB parsing; never copies anything.
9119 // as our reader is line-based, returns FALSE on EOL.
9120 // EOL is detected after skipping leading delimiters.
9121 // passing -1 as delimiter skips the whole line, and always returns FALSE.
9122 // trailing delimiter is always skipped.
9123 // result is on the data stack.
9125 //==========================================================================
9126 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
9127 ufoPush(delim
); ufoPushBool(skipLeading
);
9131 //==========================================================================
9135 // ( -- addr count )
9136 // parse with leading blanks skipping. doesn't copy anything.
9137 // return empty string on EOL.
9139 //==========================================================================
9140 void ufoCallParseName (void) {
9145 //==========================================================================
9149 // ( -- addr count TRUE / FALSE )
9150 // parse without skipping delimiters; never copies anything.
9151 // as our reader is line-based, returns FALSE on EOL.
9152 // passing 0 as delimiter skips the whole line, and always returns FALSE.
9153 // trailing delimiter is always skipped.
9155 //==========================================================================
9156 void ufoCallParse (uint32_t delim
) {
9162 //==========================================================================
9164 // ufoCallParseSkipBlanks
9166 //==========================================================================
9167 void ufoCallParseSkipBlanks (void) {
9168 UFCALL(PARSE_SKIP_BLANKS
);
9172 //==========================================================================
9174 // ufoCallParseSkipComments
9176 //==========================================================================
9177 void ufoCallParseSkipComments (void) {
9178 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9182 //==========================================================================
9184 // ufoCallParseSkipLineComments
9186 //==========================================================================
9187 void ufoCallParseSkipLineComments (void) {
9188 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9192 //==========================================================================
9194 // ufoCallParseSkipLine
9196 // to the end of line; doesn't refill
9198 //==========================================================================
9199 void ufoCallParseSkipLine (void) {
9200 UFCALL(PARSE_SKIP_LINE
);
9204 //==========================================================================
9206 // ufoCallBasedNumber
9208 // convert number from addrl+1
9209 // returns address of the first inconvertible char
9210 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
9212 //==========================================================================
9213 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
9214 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
9215 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
9216 UFCALL(PAR_BASED_NUMBER
);
9220 //==========================================================================
9224 //==========================================================================
9225 void ufoRunWord (uint32_t cfa
) {
9227 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9228 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9229 ufoMode
= UFO_MODE_NATIVE
;
9237 //==========================================================================
9241 //==========================================================================
9242 void ufoRunMacroWord (uint32_t cfa
) {
9244 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9245 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9246 ufoMode
= UFO_MODE_MACRO
;
9247 const uint32_t oisp
= ufoFileStackPos
;
9250 (void)ufoLoadNextUserLine();
9255 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
9260 //==========================================================================
9264 // check if we are currently in "MACRO" mode.
9265 // should be called from registered words.
9267 //==========================================================================
9268 int ufoIsInMacroMode (void) {
9269 return (ufoMode
== UFO_MODE_MACRO
);
9273 //==========================================================================
9275 // ufoRunInterpretLoop
9277 // run default interpret loop.
9279 //==========================================================================
9280 void ufoRunInterpretLoop (void) {
9281 if (ufoMode
== UFO_MODE_NONE
) {
9284 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
9285 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
9287 ufoMode
= UFO_MODE_NATIVE
;
9291 while (ufoFileStackPos
!= 0) ufoPopInFile();
9295 //==========================================================================
9299 //==========================================================================
9300 void ufoRunFile (const char *fname
) {
9301 if (ufoMode
== UFO_MODE_NONE
) {
9304 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
9305 ufoMode
= UFO_MODE_NATIVE
;
9308 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
9310 FILE *ufl
= fopen(ufmname
, "rb");
9312 FILE *ufl
= fopen(ufmname
, "r");
9316 ufoSetInFileNameReuse(ufmname
);
9318 ufoFileId
= ufoLastUsedFileId
;
9319 setLastIncPath(ufoInFileName
, 0);
9322 ufoFatal("cannot load source file '%s'", fname
);
9324 ufoRunInterpretLoop();