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
&& wname
!= stx
+ wnlen
) {
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 // ( !0 -- !0 ) -- jmp
3452 // ( 0 -- ) -- no jmp
3453 UFWORD(PAR_OR_BRANCH
) {
3454 if (ufoPeek() != 0) {
3455 ufoIP
= ufoImgGetU32(ufoIP
);
3463 // ( 0 -- 0 ) -- jmp
3464 // ( !0 -- ) -- no jmp
3465 UFWORD(PAR_AND_BRANCH
) {
3466 if (ufoPeek() == 0) {
3467 ufoIP
= ufoImgGetU32(ufoIP
);
3476 // ( n !0 -- ) -- no jmp
3477 UFWORD(PAR_CASE_BRANCH
) {
3478 if (ufoPop() == 0) {
3479 ufoIP
= ufoImgGetU32(ufoIP
);
3487 // ////////////////////////////////////////////////////////////////////////// //
3488 // execute words by CFA
3497 // EXECUTE-TAIL ( cfa )
3498 UFWORD(EXECUTE_TAIL
) {
3504 // (FORTH-CALL) ( pfa )
3505 UFWORD(FORTH_CALL
) {
3511 // ////////////////////////////////////////////////////////////////////////// //
3512 // word termination, locals support
3522 UFWORD(PAR_LENTER
) {
3523 // low byte of loccount is total number of locals
3524 // high byte is the number of args
3525 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3526 uint32_t acount
= (lcount
>> 8) & 0xff;
3528 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3529 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3530 ufoFatal("out of locals stack");
3533 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3534 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3535 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3536 ufoLBP
= newbp
; ufoLP
+= lcount
;
3539 while (newbp
!= ufoLBP
) {
3540 ufoLStack
[newbp
] = ufoPop();
3546 UFWORD(PAR_LLEAVE
) {
3547 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3548 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3550 ufoLBP
= ufoLStack
[ufoLBP
];
3553 //==========================================================================
3557 //==========================================================================
3558 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
3559 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3560 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3561 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3564 //==========================================================================
3568 //==========================================================================
3569 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
3570 const uint32_t value
= ufoPop();
3571 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3572 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3573 ufoLStack
[ufoLBP
+ lidx
] = value
;
3578 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3582 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3585 // ////////////////////////////////////////////////////////////////////////// //
3586 // stack manipulation
3591 UFWORD(DUP
) { ufoDup(); }
3593 // ( n -- n n ) | ( 0 -- 0 )
3594 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3596 // ( n0 n1 -- n0 n1 n0 n1 )
3597 UFWORD(DDUP
) { ufo2Dup(); }
3600 UFWORD(DROP
) { ufoDrop(); }
3603 UFWORD(DDROP
) { ufo2Drop(); }
3605 // ( n0 n1 -- n1 n0 )
3606 UFWORD(SWAP
) { ufoSwap(); }
3608 // ( n0 n1 -- n1 n0 )
3609 UFWORD(DSWAP
) { ufo2Swap(); }
3611 // ( n0 n1 -- n0 n1 n0 )
3612 UFWORD(OVER
) { ufoOver(); }
3614 // ( n0 n1 -- n0 n1 n0 )
3615 UFWORD(DOVER
) { ufo2Over(); }
3617 // ( n0 n1 n2 -- n1 n2 n0 )
3618 UFWORD(ROT
) { ufoRot(); }
3620 // ( n0 n1 n2 -- n2 n0 n1 )
3621 UFWORD(NROT
) { ufoNRot(); }
3625 UFWORD(RDUP
) { ufoRDup(); }
3628 UFWORD(RDROP
) { ufoRDrop(); }
3632 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3635 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3638 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3643 const uint32_t n
= ufoPop();
3644 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3645 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3651 const uint32_t n
= ufoPop();
3652 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3653 const uint32_t rp
= ufoRP
- n
- 1u;
3654 ufoPush(ufoRStack
[rp
]);
3660 const uint32_t n
= ufoPop();
3661 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3663 case 0: break; // do nothing
3664 case 1: ufoSwap(); break;
3665 case 2: ufoRot(); break;
3668 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3669 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3670 ufoDStack
[ufoSP
- 1u] = val
;
3679 const uint32_t n
= ufoPop();
3680 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3682 const uint32_t rp
= ufoRP
- n
- 1u;
3683 const uint32_t val
= ufoRStack
[rp
];
3684 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3685 ufoRStack
[ufoRP
- 1u] = val
;
3690 // ( | a b -- | b a )
3692 const uint32_t b
= ufoRPop();
3693 const uint32_t a
= ufoRPop();
3694 ufoRPush(b
); ufoRPush(a
);
3698 // ( | a b -- | a b a )
3700 const uint32_t b
= ufoRPop();
3701 const uint32_t a
= ufoRPop();
3702 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3706 // ( | a b c -- | b c a )
3708 const uint32_t c
= ufoRPop();
3709 const uint32_t b
= ufoRPop();
3710 const uint32_t a
= ufoRPop();
3711 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3715 // ( | a b c -- | c a b )
3717 const uint32_t c
= ufoRPop();
3718 const uint32_t b
= ufoRPop();
3719 const uint32_t a
= ufoRPop();
3720 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3724 // ////////////////////////////////////////////////////////////////////////// //
3731 ufoPushBool(ufoLoadNextLine(1));
3736 UFWORD(REFILL_NOCROSS
) {
3737 ufoPushBool(ufoLoadNextLine(0));
3743 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3748 UFWORD(TIB_PEEKCH
) {
3749 ufoPush(ufoTibPeekCh());
3754 UFWORD(TIB_PEEKCH_OFS
) {
3755 const uint32_t ofs
= ufoPop();
3756 ufoPush(ufoTibPeekChOfs(ofs
));
3762 ufoPush(ufoTibGetCh());
3767 UFWORD(TIB_SKIPCH
) {
3772 // ////////////////////////////////////////////////////////////////////////// //
3776 //==========================================================================
3780 //==========================================================================
3781 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3782 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3786 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3787 // does base TIB parsing; never copies anything.
3788 // as our reader is line-based, returns FALSE on EOL.
3789 // EOL is detected after skipping leading delimiters.
3790 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3791 // trailing delimiter is always skipped.
3793 const uint32_t skipDelim
= ufoPop();
3794 const uint32_t delim
= ufoPop();
3797 if (delim
== 0 || delim
> 0xffU
) {
3799 while (ufoTibGetCh() != 0) {}
3802 ch
= ufoTibPeekCh();
3803 // skip initial delimiters
3805 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3807 ch
= ufoTibPeekCh();
3814 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3816 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3819 ch
= ufoTibPeekCh();
3822 if (ch
!= 0) ufoTibSkipCh();
3830 // PARSE-SKIP-BLANKS
3832 UFWORD(PARSE_SKIP_BLANKS
) {
3833 uint8_t ch
= ufoTibPeekCh();
3834 while (ch
!= 0 && ch
<= 32) {
3836 ch
= ufoTibPeekCh();
3840 //==========================================================================
3842 // ufoParseMLComment
3844 // initial two chars are skipped
3846 //==========================================================================
3847 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3850 while (level
!= 0) {
3854 UFCALL(REFILL_NOCROSS
);
3855 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3857 ufoFatal("unexpected end of line in comment");
3860 ch1
= ufoTibPeekCh();
3861 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3862 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3863 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3868 // (PARSE-SKIP-COMMENTS)
3869 // ( allow-multiline? -- )
3870 // skip all blanks and comments
3871 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3872 const uint32_t allowMulti
= ufoPop();
3874 ch
= ufoTibPeekCh();
3876 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3881 ch
= ufoTibPeekCh();
3883 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3885 } else if (ch
== '(') {
3887 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3888 ufoTibPeekChOfs(0));
3890 ch1
= ufoTibPeekChOfs(1);
3892 // single-line comment
3893 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3894 ch
= ufoTibPeekCh();
3895 } else if ((ch1
== '*' || ch1
== '(') && ufoTibPeekChOfs(2) <= 32) {
3896 // possibly multiline
3897 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3898 ufoParseMLComment(allowMulti
, (ch1
== '('));
3899 ch
= ufoTibPeekCh();
3903 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3904 // single-line comment
3905 while (ch
!= 0) ch
= ufoTibGetCh();
3906 } else if (ch
== '-' && ufoTibPeekChOfs(1) == ch
&& ufoTibPeekChOfs(2) <= 32) {
3908 while (ch
!= 0) ch
= ufoTibGetCh();
3909 } else if ((ch
== ';' || ch
== '/') && ufoTibPeekChOfs(1) == ch
) {
3911 while (ch
!= 0) ch
= ufoTibGetCh();
3917 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3923 UFWORD(PARSE_SKIP_LINE
) {
3924 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3925 if (ufoPop() != 0) {
3931 // ( -- addr count )
3932 // parse with leading blanks skipping. doesn't copy anything.
3933 // return empty string on EOL.
3934 UFWORD(PARSE_NAME
) {
3935 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3936 if (ufoPop() == 0) {
3943 // ( delim -- addr count TRUE / FALSE )
3944 // parse without skipping delimiters; never copies anything.
3945 // as our reader is line-based, returns FALSE on EOL.
3946 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3947 // trailing delimiter is always skipped.
3949 ufoPushBool(0); UFCALL(PAR_PARSE
);
3953 // ////////////////////////////////////////////////////////////////////////// //
3959 UFWORD(PAR_NORM_EMIT_CHAR
) {
3960 uint32_t ch
= ufoPop()&0xffU
;
3961 if (ch
< 32 || ch
== 127) {
3962 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
3967 // (NORM-XEMIT-CHAR)
3969 UFWORD(PAR_NORM_XEMIT_CHAR
) {
3970 uint32_t ch
= ufoPop()&0xffU
;
3971 if (ch
< 32 || ch
== 127) ch
= '?';
3978 uint32_t ch
= ufoPop()&0xffU
;
3979 ufoLastEmitWasCR
= (ch
== 10);
3986 ufoPushBool(ufoLastEmitWasCR
);
3992 ufoLastEmitWasCR
= !!ufoPop();
3997 UFWORD(FLUSH_EMIT
) {
4002 // ////////////////////////////////////////////////////////////////////////// //
4006 #define UF_UMATH(name_,op_) \
4008 const uint32_t a = ufoPop(); \
4012 #define UF_BMATH(name_,op_) \
4014 const uint32_t b = ufoPop(); \
4015 const uint32_t a = ufoPop(); \
4019 #define UF_BDIV(name_,op_) \
4021 const uint32_t b = ufoPop(); \
4022 const uint32_t a = ufoPop(); \
4023 if (b == 0) ufoFatal("division by zero"); \
4027 #define UFO_POP_U64() ({ \
4028 const uint32_t hi_ = ufoPop(); \
4029 const uint32_t lo_ = ufoPop(); \
4030 (((uint64_t)hi_ << 32) | lo_); \
4033 // this is UB by the idiotic C standard. i don't care.
4034 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
4036 #define UFO_PUSH_U64(vn_) do { \
4037 ufoPush((uint32_t)(vn_)); \
4038 ufoPush((uint32_t)((vn_) >> 32)); \
4041 // this is UB by the idiotic C standard. i don't care.
4042 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
4046 UF_BMATH(PLUS
, a
+ b
);
4050 UF_BMATH(MINUS
, a
- b
);
4054 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
4058 UF_BMATH(UMUL
, a
* b
);
4062 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
4066 UF_BDIV(UDIV
, a
/ b
);
4070 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
4074 UF_BDIV(UMOD
, a
% b
);
4077 // ( a b -- a/b, a%b )
4079 const int32_t b
= (int32_t)ufoPop();
4080 const int32_t a
= (int32_t)ufoPop();
4081 if (b
== 0) ufoFatal("division by zero");
4082 ufoPush((uint32_t)(a
/b
));
4083 ufoPush((uint32_t)(a
%b
));
4087 // ( a b -- a/b, a%b )
4089 const uint32_t b
= ufoPop();
4090 const uint32_t a
= ufoPop();
4091 if (b
== 0) ufoFatal("division by zero");
4092 ufoPush((uint32_t)(a
/b
));
4093 ufoPush((uint32_t)(a
%b
));
4097 // ( a b c -- a*b/c )
4098 // this uses 64-bit intermediate value
4100 const int32_t c
= (int32_t)ufoPop();
4101 const int32_t b
= (int32_t)ufoPop();
4102 const int32_t a
= (int32_t)ufoPop();
4103 if (c
== 0) ufoFatal("division by zero");
4104 int64_t xval
= a
; xval
*= b
; xval
/= c
;
4105 ufoPush((uint32_t)(int32_t)xval
);
4109 // ( a b c -- a*b/c )
4110 // this uses 64-bit intermediate value
4112 const uint32_t c
= ufoPop();
4113 const uint32_t b
= ufoPop();
4114 const uint32_t a
= ufoPop();
4115 if (c
== 0) ufoFatal("division by zero");
4116 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
4117 ufoPush((uint32_t)xval
);
4121 // ( a b c -- a*b/c a*b%c )
4122 // this uses 64-bit intermediate value
4124 const int32_t c
= (int32_t)ufoPop();
4125 const int32_t b
= (int32_t)ufoPop();
4126 const int32_t a
= (int32_t)ufoPop();
4127 if (c
== 0) ufoFatal("division by zero");
4128 int64_t xval
= a
; xval
*= b
;
4129 ufoPush((uint32_t)(int32_t)(xval
/ c
));
4130 ufoPush((uint32_t)(int32_t)(xval
% c
));
4134 // ( a b c -- a*b/c )
4135 // this uses 64-bit intermediate value
4136 UFWORD(UMULDIVMOD
) {
4137 const uint32_t c
= ufoPop();
4138 const uint32_t b
= ufoPop();
4139 const uint32_t a
= ufoPop();
4140 if (c
== 0) ufoFatal("division by zero");
4141 uint64_t xval
= a
; xval
*= b
;
4142 ufoPush((uint32_t)(xval
/ c
));
4143 ufoPush((uint32_t)(xval
% c
));
4147 // ( a b -- lo(a*b) hi(a*b) )
4148 // this leaves 64-bit result
4150 const int32_t b
= (int32_t)ufoPop();
4151 const int32_t a
= (int32_t)ufoPop();
4152 int64_t xval
= a
; xval
*= b
;
4157 // ( a b -- lo(a*b) hi(a*b) )
4158 // this leaves 64-bit result
4160 const uint32_t b
= ufoPop();
4161 const uint32_t a
= ufoPop();
4162 uint64_t xval
= a
; xval
*= b
;
4167 // ( alo ahi b -- a/b a%b )
4169 const int32_t b
= (int32_t)ufoPop();
4170 if (b
== 0) ufoFatal("division by zero");
4171 int64_t a
= UFO_POP_I64();
4172 int32_t adiv
= (int32_t)(a
/ b
);
4173 int32_t amod
= (int32_t)(a
% b
);
4174 ufoPush((uint32_t)adiv
);
4175 ufoPush((uint32_t)amod
);
4179 // ( alo ahi b -- a/b a%b )
4181 const uint32_t b
= ufoPop();
4182 if (b
== 0) ufoFatal("division by zero");
4183 uint64_t a
= UFO_POP_U64();
4184 uint32_t adiv
= (uint32_t)(a
/ b
);
4185 uint32_t amod
= (uint32_t)(a
% b
);
4191 // ( alo ahi u -- lo hi )
4193 const uint32_t b
= ufoPop();
4194 uint64_t a
= UFO_POP_U64();
4200 // ( lo0 hi0 lo1 hi1 -- lo hi )
4202 uint64_t n1
= UFO_POP_U64();
4203 uint64_t n0
= UFO_POP_U64();
4209 // ( lo0 hi0 lo1 hi1 -- lo hi )
4211 uint64_t n1
= UFO_POP_U64();
4212 uint64_t n0
= UFO_POP_U64();
4218 // ( lo0 hi0 lo1 hi1 -- bool )
4220 uint64_t n1
= UFO_POP_U64();
4221 uint64_t n0
= UFO_POP_U64();
4222 ufoPushBool(n0
== n1
);
4226 // ( lo0 hi0 lo1 hi1 -- bool )
4228 int64_t n1
= UFO_POP_I64();
4229 int64_t n0
= UFO_POP_I64();
4230 ufoPushBool(n0
< n1
);
4234 // ( lo0 hi0 lo1 hi1 -- bool )
4236 int64_t n1
= UFO_POP_I64();
4237 int64_t n0
= UFO_POP_I64();
4238 ufoPushBool(n0
<= n1
);
4242 // ( lo0 hi0 lo1 hi1 -- bool )
4244 uint64_t n1
= UFO_POP_U64();
4245 uint64_t n0
= UFO_POP_U64();
4246 ufoPushBool(n0
< n1
);
4250 // ( lo0 hi0 lo1 hi1 -- bool )
4252 uint64_t n1
= UFO_POP_U64();
4253 uint64_t n0
= UFO_POP_U64();
4254 ufoPushBool(n0
<= n1
);
4258 // ( dlo dhi n -- nmod ndiv )
4259 // rounds toward zero
4261 const int32_t n
= (int32_t)ufoPop();
4262 if (n
== 0) ufoFatal("division by zero");
4263 int64_t d
= UFO_POP_I64();
4264 int32_t ndiv
= (int32_t)(d
/ n
);
4265 int32_t nmod
= (int32_t)(d
% n
);
4271 // ( dlo dhi n -- nmod ndiv )
4272 // rounds toward negative infinity
4274 const int32_t n
= (int32_t)ufoPop();
4275 if (n
== 0) ufoFatal("division by zero");
4276 int64_t d
= UFO_POP_I64();
4277 int32_t ndiv
= (int32_t)(d
/ n
);
4278 int32_t nmod
= (int32_t)(d
% n
);
4279 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
4288 // ////////////////////////////////////////////////////////////////////////// //
4289 // simple logic and bit manipulation
4292 #define UF_CMP(name_,op_) \
4294 const uint32_t b = ufoPop(); \
4295 const uint32_t a = ufoPop(); \
4301 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
4305 UF_CMP(ULESS
, a
< b
);
4309 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
4313 UF_CMP(UGREAT
, a
> b
);
4317 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
4321 UF_CMP(ULESSEQU
, a
<= b
);
4325 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
4329 UF_CMP(UGREATEQU
, a
>= b
);
4333 UF_CMP(EQU
, a
== b
);
4337 UF_CMP(NOTEQU
, a
!= b
);
4342 const uint32_t a
= ufoPop();
4343 ufoPushBool(a
== 0);
4348 UFWORD(ZERO_NOTEQU
) {
4349 const uint32_t a
= ufoPop();
4350 ufoPushBool(a
!= 0);
4355 UF_CMP(LOGAND
, a
&& b
);
4359 UF_CMP(LOGOR
, a
|| b
);
4364 const uint32_t b
= ufoPop();
4365 const uint32_t a
= ufoPop();
4372 const uint32_t b
= ufoPop();
4373 const uint32_t a
= ufoPop();
4380 const uint32_t b
= ufoPop();
4381 const uint32_t a
= ufoPop();
4388 const uint32_t a
= ufoPop();
4394 // arithmetic shift; positive `n` shifts to the left
4396 int32_t c
= (int32_t)ufoPop();
4399 int32_t n
= (int32_t)ufoPop();
4401 if (n
< 0) n
= -1; else n
= 0;
4403 n
>>= (uint8_t)(-c
);
4405 ufoPush((uint32_t)n
);
4408 uint32_t u
= ufoPop();
4420 // logical shift; positive `n` shifts to the left
4422 int32_t c
= (int32_t) ufoPop();
4423 uint32_t u
= ufoPop();
4429 u
>>= (uint8_t)(-c
);
4443 // ////////////////////////////////////////////////////////////////////////// //
4444 // string unescaping
4448 // ( addr count -- addr count )
4449 UFWORD(PAR_UNESCAPE
) {
4450 const uint32_t count
= ufoPop();
4451 const uint32_t addr
= ufoPeek();
4452 if ((count
& ((uint32_t)1<<31)) == 0) {
4453 const uint32_t eaddr
= addr
+ count
;
4454 uint32_t caddr
= addr
;
4455 uint32_t daddr
= addr
;
4456 while (caddr
!= eaddr
) {
4457 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4458 if (ch
== '\\' && caddr
!= eaddr
) {
4459 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4461 case 'r': ch
= '\r'; break;
4462 case 'n': ch
= '\n'; break;
4463 case 't': ch
= '\t'; break;
4464 case 'e': ch
= '\x1b'; break;
4465 case '`': ch
= '"'; break; // special escape to insert double-quote
4466 case '"': ch
= '"'; break;
4467 case '\\': ch
= '\\'; break;
4469 if (eaddr
- daddr
>= 1) {
4470 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
4471 if (dg0
< 0) ufoFatal("invalid hex string escape");
4472 if (eaddr
- daddr
>= 2) {
4473 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
4474 if (dg1
< 0) ufoFatal("invalid hex string escape");
4475 ch
= (uint8_t)(dg0
* 16 + dg1
);
4482 ufoFatal("invalid hex string escape");
4485 default: ufoFatal("invalid string escape");
4488 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
4490 ufoPush(daddr
- addr
);
4497 // ////////////////////////////////////////////////////////////////////////// //
4498 // numeric conversions
4501 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4502 UFWORD(PAR_BASED_NUMBER
) {
4503 const uint32_t xbase
= ufoPop();
4504 const uint32_t allowSign
= ufoPop();
4505 int32_t count
= (int32_t)ufoPop();
4506 uint32_t addr
= ufoPop();
4512 if (allowSign
&& count
> 1) {
4513 ch
= ufoImgGetU8Ext(addr
);
4514 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
4515 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
4518 // special-based numbers
4519 ch
= ufoImgGetU8Ext(addr
);
4520 if (count
>= 3 && ch
== '0') {
4521 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4522 case 'x': case 'X': base
= 16; break;
4523 case 'o': case 'O': base
= 8; break;
4524 case 'b': case 'B': base
= 2; break;
4525 case 'd': case 'D': base
= 10; break;
4528 if (base
&& digitInBase((char)ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u), base
) >= 0) {
4529 addr
+= 2; count
-= 2;
4533 } else if (count
>= 2 && ch
== '$') {
4535 addr
+= 1u; count
-= 1;
4536 } else if (count
>= 2 && ch
== '#') {
4538 addr
+= 1u; count
-= 1;
4539 } else if (count
>= 2 && ch
== '%') {
4541 addr
+= 1u; count
-= 1;
4542 } else if (count
>= 3 && ch
== '&') {
4543 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4544 case 'h': case 'H': base
= 16; break;
4545 case 'o': case 'O': base
= 8; break;
4546 case 'b': case 'B': base
= 2; break;
4547 case 'd': case 'D': base
= 10; break;
4550 if (base
) { addr
+= 2u; count
-= 2; }
4552 if (!base
&& count
> 2 && ch
>= '0' && ch
<= '9') {
4553 ch
= ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u);
4555 case 'b': case 'B': if (xbase
< 12) base
= 2; break;
4556 case 'o': case 'O': if (xbase
< 25) base
= 8; break;
4557 case 'h': case 'H': if (xbase
< 18) base
= 16; break;
4559 if (base
) count
-= 1;
4563 if (!base
&& xbase
< 255) base
= xbase
;
4565 if (count
<= 0 || base
< 1 || base
> 36) {
4569 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
4570 while (!error
&& count
!= 0) {
4571 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
4573 error
= 1; wasUnder
= 0; wasDig
= 1;
4574 dig
= digitInBase((char)ch
, (int)base
);
4576 nc
= n
* (uint32_t)base
;
4578 nc
+= (uint32_t)dig
;
4591 if (!error
&& wasDig
&& !wasUnder
) {
4592 if (allowSign
&& neg
) n
= ~n
+ 1u;
4602 // ////////////////////////////////////////////////////////////////////////// //
4603 // compiler-related, dictionary-related
4606 static char ufoWNameBuf
[256];
4608 // (CREATE-WORD-HEADER)
4609 // ( addr count word-flags -- )
4610 UFWORD(PAR_CREATE_WORD_HEADER
) {
4611 const uint32_t flags
= ufoPop();
4612 const uint32_t wlen
= ufoPop();
4613 const uint32_t waddr
= ufoPop();
4614 if (wlen
== 0) ufoFatal("word name expected");
4615 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4616 // copy to separate buffer
4617 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4618 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4620 ufoWNameBuf
[wlen
] = 0;
4621 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4624 // (CREATE-NAMELESS-WORD-HEADER)
4625 // ( word-flags -- )
4626 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4627 const uint32_t flags
= ufoPop();
4628 ufoCreateWordHeader("", flags
);
4632 // ( addr count -- cfa TRUE / FALSE)
4634 const uint32_t wlen
= ufoPop();
4635 const uint32_t waddr
= ufoPop();
4636 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4637 // copy to separate buffer
4638 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4639 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4641 ufoWNameBuf
[wlen
] = 0;
4642 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4654 // (FIND-WORD-IN-VOC)
4655 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4656 // find only in the given voc; no name resolution
4657 UFWORD(FIND_WORD_IN_VOC
) {
4658 const uint32_t allowHidden
= ufoPop();
4659 const uint32_t vocid
= ufoPop();
4660 const uint32_t wlen
= ufoPop();
4661 const uint32_t waddr
= ufoPop();
4662 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4663 // copy to separate buffer
4664 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4665 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4667 ufoWNameBuf
[wlen
] = 0;
4668 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4680 // (FIND-WORD-IN-VOC-AND-PARENTS)
4681 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4682 // find only in the given voc; no name resolution
4683 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4684 const uint32_t allowHidden
= ufoPop();
4685 const uint32_t vocid
= ufoPop();
4686 const uint32_t wlen
= ufoPop();
4687 const uint32_t waddr
= ufoPop();
4688 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4689 // copy to separate buffer
4690 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4691 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4693 ufoWNameBuf
[wlen
] = 0;
4694 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4707 // ////////////////////////////////////////////////////////////////////////// //
4708 // more compiler words
4711 // ////////////////////////////////////////////////////////////////////////// //
4712 // vocabulary and wordlist utilities
4717 UFWORD(PAR_GET_VSP
) {
4723 UFWORD(PAR_SET_VSP
) {
4724 const uint32_t vsp
= ufoPop();
4725 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4731 UFWORD(PAR_VSP_LOAD
) {
4732 const uint32_t vsp
= ufoPop();
4733 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4734 ufoPush(ufoVocStack
[vsp
]);
4739 UFWORD(PAR_VSP_STORE
) {
4740 const uint32_t vsp
= ufoPop();
4741 const uint32_t value
= ufoPop();
4742 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4743 ufoVocStack
[vsp
] = value
;
4747 // ////////////////////////////////////////////////////////////////////////// //
4748 // word field address conversion
4754 const uint32_t cfa
= ufoPop();
4755 ufoPush(UFO_CFA_TO_PFA(cfa
));
4761 const uint32_t cfa
= ufoPop();
4762 ufoPush(UFO_CFA_TO_NFA(cfa
));
4768 const uint32_t cfa
= ufoPop();
4769 ufoPush(UFO_CFA_TO_LFA(cfa
));
4773 // ( cfa -- wend-addr )
4775 const uint32_t cfa
= ufoPop();
4776 ufoPush(ufoGetWordEndAddr(cfa
));
4782 const uint32_t pfa
= ufoPop();
4783 ufoPush(UFO_PFA_TO_CFA(pfa
));
4789 const uint32_t pfa
= ufoPop();
4790 const uint32_t cfa
= UFO_PFA_TO_CFA(pfa
);
4791 ufoPush(UFO_CFA_TO_NFA(cfa
));
4797 const uint32_t nfa
= ufoPop();
4798 ufoPush(UFO_NFA_TO_CFA(nfa
));
4804 const uint32_t nfa
= ufoPop();
4805 const uint32_t cfa
= UFO_NFA_TO_CFA(nfa
);
4806 ufoPush(UFO_CFA_TO_PFA(cfa
));
4812 const uint32_t nfa
= ufoPop();
4813 ufoPush(UFO_NFA_TO_LFA(nfa
));
4819 const uint32_t lfa
= ufoPop();
4820 ufoPush(UFO_LFA_TO_CFA(lfa
));
4826 const uint32_t lfa
= ufoPop();
4827 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4828 ufoPush(UFO_CFA_TO_PFA(cfa
));
4834 const uint32_t lfa
= ufoPop();
4835 ufoPush(UFO_LFA_TO_BFA(lfa
));
4841 const uint32_t lfa
= ufoPop();
4842 ufoPush(UFO_LFA_TO_XFA(lfa
));
4848 const uint32_t lfa
= ufoPop();
4849 ufoPush(UFO_LFA_TO_YFA(lfa
));
4855 const uint32_t lfa
= ufoPop();
4856 ufoPush(UFO_LFA_TO_NFA(lfa
));
4860 // ( ip -- nfa / 0 )
4862 const uint32_t ip
= ufoPop();
4863 ufoPush(ufoFindWordForIP(ip
));
4867 // ( ip -- addr count line TRUE / FALSE )
4868 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4869 UFWORD(IP2FILELINE
) {
4870 const uint32_t ip
= ufoPop();
4872 const char *fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
4873 if (fname
!= NULL
) {
4875 uint32_t addr
= ufoPeek();
4877 while (*fname
!= 0) {
4878 ufoImgPutU8(addr
, *(const unsigned char *)fname
);
4879 fname
+= 1u; addr
+= 1u; count
+= 1u;
4881 ufoImgPutU8(addr
, 0); // just in case
4891 // IP->FILE-HASH/LINE
4892 // ( ip -- len hash line TRUE / FALSE )
4893 UFWORD(IP2FILEHASHLINE
) {
4894 const uint32_t ip
= ufoPop();
4895 uint32_t fline
, fhash
, flen
;
4896 const char *fname
= ufoFindFileForIP(ip
, &fline
, &flen
, &fhash
);
4897 if (fname
!= NULL
) {
4908 // ////////////////////////////////////////////////////////////////////////// //
4909 // string operations
4912 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4913 uint32_t hash
= 0x29a;
4914 if ((size
& ((uint32_t)1<<31)) == 0) {
4916 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4919 addr
+= 1u; size
-= 1u;
4929 //==========================================================================
4933 //==========================================================================
4934 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
4936 if ((count
& ((uint32_t)1<<31)) == 0) {
4938 while (res
!= 0 && count
!= 0) {
4939 res
= (toUpperU8(ufoImgGetU8Ext(addr0
)) == toUpperU8(ufoImgGetU8Ext(addr1
)));
4940 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
4949 // ( a0 c0 a1 c1 -- bool )
4951 int32_t c1
= (int32_t)ufoPop();
4952 uint32_t a1
= ufoPop();
4953 int32_t c0
= (int32_t)ufoPop();
4954 uint32_t a0
= ufoPop();
4959 while (res
!= 0 && c0
!= 0) {
4960 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4961 a0
+= 1; a1
+= 1; c0
-= 1;
4970 // ( a0 c0 a1 c1 -- bool )
4972 int32_t c1
= (int32_t)ufoPop();
4973 uint32_t a1
= ufoPop();
4974 int32_t c0
= (int32_t)ufoPop();
4975 uint32_t a0
= ufoPop();
4980 while (res
!= 0 && c0
!= 0) {
4981 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4982 a0
+= 1; a1
+= 1; c0
-= 1;
4990 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4991 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4992 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4993 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4995 const uint32_t pcount
= ufoPop();
4996 const uint32_t paddr
= ufoPop();
4997 const uint32_t tcount
= ufoPop();
4998 const uint32_t taddr
= ufoPop();
4999 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
5000 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
5001 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
5003 ufoPush(tcount
- f
);
5015 // ( addr count -- hash )
5017 uint32_t count
= ufoPop();
5018 uint32_t addr
= ufoPop();
5019 ufoPush(ufoHashBuf(addr
, count
, 0));
5023 // ( addr count -- hash )
5025 uint32_t count
= ufoPop();
5026 uint32_t addr
= ufoPop();
5027 ufoPush(ufoHashBuf(addr
, count
, 0x20));
5031 // ////////////////////////////////////////////////////////////////////////// //
5032 // conditional defines
5035 typedef struct UForthCondDefine_t UForthCondDefine
;
5036 struct UForthCondDefine_t
{
5040 UForthCondDefine
*next
;
5043 static UForthCondDefine
*ufoCondDefines
= NULL
;
5044 static char ufoErrMsgBuf
[4096];
5047 //==========================================================================
5051 //==========================================================================
5052 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
5053 const unsigned char *s0
= (const unsigned char *)str0
;
5054 const unsigned char *s1
= (const unsigned char *)str1
;
5055 while (*s0
&& *s1
) {
5056 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
5059 return (*s0
== 0 && *s1
== 0);
5063 //==========================================================================
5067 //==========================================================================
5068 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
5070 if ((count
& ((uint32_t)1<<31)) == 0) {
5071 const unsigned char *src
= (const unsigned char *)buf
;
5073 while (res
!= 0 && count
!= 0) {
5074 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
5075 src
+= 1; addr
+= 1u; count
-= 1u;
5084 //==========================================================================
5086 // ufoClearCondDefines
5088 //==========================================================================
5089 static void ufoClearCondDefines (void) {
5090 while (ufoCondDefines
) {
5091 UForthCondDefine
*df
= ufoCondDefines
;
5092 ufoCondDefines
= df
->next
;
5093 if (df
->name
) free(df
->name
);
5099 //==========================================================================
5103 //==========================================================================
5104 int ufoHasCondDefine (const char *name
) {
5106 if (name
!= NULL
&& name
[0] != 0) {
5107 const size_t nlen
= strlen(name
);
5109 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5110 UForthCondDefine
*dd
= ufoCondDefines
;
5111 while (res
== 0 && dd
!= NULL
) {
5112 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5113 res
= ufoStrEquCI(name
, dd
->name
);
5123 //==========================================================================
5127 //==========================================================================
5128 void ufoCondDefine (const char *name
) {
5129 if (name
!= NULL
&& name
[0] != 0) {
5130 const size_t nlen
= strlen(name
);
5131 if (nlen
> 255) ufoFatal("conditional define name too long");
5132 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5133 UForthCondDefine
*dd
= ufoCondDefines
;
5135 while (res
== 0 && dd
!= NULL
) {
5136 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5137 res
= ufoStrEquCI(name
, dd
->name
);
5143 dd
= calloc(1, sizeof(UForthCondDefine
));
5144 if (dd
== NULL
) ufoFatal("out of memory for defines");
5145 dd
->name
= strdup(name
);
5146 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5147 dd
->namelen
= (uint32_t)nlen
;
5149 dd
->next
= ufoCondDefines
;
5150 ufoCondDefines
= dd
;
5156 //==========================================================================
5160 //==========================================================================
5161 void ufoCondUndef (const char *name
) {
5162 if (name
!= NULL
&& name
[0] != 0) {
5163 const size_t nlen
= strlen(name
);
5165 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
5166 UForthCondDefine
*dd
= ufoCondDefines
;
5167 UForthCondDefine
*prev
= NULL
;
5168 while (dd
!= NULL
) {
5169 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
5170 if (ufoStrEquCI(name
, dd
->name
)) {
5171 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
5177 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
5185 // ( addr count -- )
5186 UFWORD(PAR_DLR_DEFINE
) {
5187 uint32_t count
= ufoPop();
5188 uint32_t addr
= ufoPop();
5189 if (count
== 0) ufoFatal("empty define");
5190 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5191 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5192 UForthCondDefine
*dd
;
5193 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5194 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5195 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
5199 dd
= calloc(1, sizeof(UForthCondDefine
));
5200 if (dd
== NULL
) ufoFatal("out of memory for defines");
5201 dd
->name
= calloc(1, count
+ 1u);
5202 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5203 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5204 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5206 dd
->namelen
= count
;
5208 dd
->next
= ufoCondDefines
;
5209 ufoCondDefines
= dd
;
5213 // ( addr count -- )
5214 UFWORD(PAR_DLR_UNDEF
) {
5215 uint32_t count
= ufoPop();
5216 uint32_t addr
= ufoPop();
5217 if (count
== 0) ufoFatal("empty define");
5218 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5219 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5220 UForthCondDefine
*prev
= NULL
;
5221 UForthCondDefine
*dd
;
5222 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
5223 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5224 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
5225 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
5235 // ( addr count -- bool )
5236 UFWORD(PAR_DLR_DEFINEDQ
) {
5237 uint32_t count
= ufoPop();
5238 uint32_t addr
= ufoPop();
5239 if (count
== 0) ufoFatal("empty define");
5240 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
5241 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
5243 UForthCondDefine
*dd
= ufoCondDefines
;
5244 while (!found
&& dd
!= NULL
) {
5245 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
5246 found
= ufoBufEquCI(addr
, count
, dd
->name
);
5254 // ////////////////////////////////////////////////////////////////////////// //
5259 // ( addr count -- )
5261 uint32_t count
= ufoPop();
5262 uint32_t addr
= ufoPop();
5263 if (count
& (1u<<31)) ufoFatal("invalid error message");
5264 if (count
== 0) ufoFatal("some error");
5265 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
5266 for (uint32_t f
= 0; f
< count
; f
+= 1) {
5267 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
5269 ufoErrMsgBuf
[count
] = 0;
5270 ufoFatal("%s", ufoErrMsgBuf
);
5273 // ////////////////////////////////////////////////////////////////////////// //
5277 static char ufoFNameBuf
[4096];
5280 //==========================================================================
5282 // ufoScanIncludeFileName
5284 // `*psys` and `*psoft` must be initialised!
5286 //==========================================================================
5287 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
5288 uint32_t *psys
, uint32_t *psoft
)
5292 ufo_assert(dest
!= NULL
);
5293 ufo_assert(destsz
> 0);
5295 while (count
!= 0) {
5296 ch
= ufoImgGetU8Ext(addr
);
5298 //if (system) ufoFatal("invalid file name (duplicate system mark)");
5300 } else if (ch
== '?') {
5301 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
5307 addr
+= 1; count
-= 1;
5308 ch
= ufoImgGetU8Ext(addr
);
5309 } while (ch
<= 32 && count
!= 0);
5312 if (count
== 0) ufoFatal("empty include file name");
5313 if (count
>= destsz
) ufoFatal("include file name too long");
5316 while (count
!= 0) {
5317 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
5318 addr
+= 1; count
-= 1;
5324 // (INCLUDE-LINE-FOFS)
5326 UFWORD(PAR_INCLUDE_LINE_FOFS
) {
5327 ufoPush((uint32_t)(int32_t)ufoCurrIncludeLineFileOfs
);
5330 // (INCLUDE-LINE-SEEK)
5332 UFWORD(PAR_INCLUDE_LINE_SEEK
) {
5333 uint32_t fofs
= ufoPop();
5334 uint32_t lidx
= ufoPop();
5335 if (lidx
>= 0x0fffffffU
) lidx
= 0;
5336 if (ufoInFile
== NULL
) ufoFatal("cannot seek without opened include file");
5337 if (fseek(ufoInFile
, (long)fofs
, SEEK_SET
) != 0) {
5338 ufoFatal("error seeking in include file");
5340 ufoInFileLine
= lidx
;
5345 // return number of items in include stack
5346 UFWORD(PAR_INCLUDE_DEPTH
) {
5347 ufoPush(ufoFileStackPos
);
5350 // (INCLUDE-FILE-ID)
5351 // ( isp -- id ) -- isp 0 is current, then 1, etc.
5352 // each include file has unique non-zero id.
5353 UFWORD(PAR_INCLUDE_FILE_ID
) {
5354 const uint32_t isp
= ufoPop();
5357 } else if (isp
<= ufoFileStackPos
) {
5358 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5361 ufoFatal("invalid include stack index");
5365 // (INCLUDE-FILE-LINE)
5367 UFWORD(PAR_INCLUDE_FILE_LINE
) {
5368 const uint32_t isp
= ufoPop();
5370 ufoPush(ufoInFileLine
);
5371 } else if (isp
<= ufoFileStackPos
) {
5372 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5373 ufoPush(stk
->fline
);
5375 ufoFatal("invalid include stack index");
5379 // (INCLUDE-FILE-NAME)
5380 // ( isp -- addr count )
5381 // current file name; at PAD
5382 UFWORD(PAR_INCLUDE_FILE_NAME
) {
5383 const uint32_t isp
= ufoPop();
5384 const char *fname
= NULL
;
5386 fname
= ufoInFileName
;
5387 } else if (isp
<= ufoFileStackPos
) {
5388 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
5391 ufoFatal("invalid include stack index");
5394 uint32_t addr
= ufoPop();
5396 if (fname
!= NULL
) {
5397 while (fname
[count
] != 0) {
5398 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
5402 ufoImgPutU8Ext(addr
+ count
, 0);
5408 // (INCLUDE-BUILD-NAME)
5409 // ( addr count soft? system? -- addr count )
5411 UFWORD(PAR_INCLUDE_BUILD_NAME
) {
5412 uint32_t system
= ufoPop();
5413 uint32_t softinclude
= ufoPop();
5414 uint32_t count
= ufoPop();
5415 uint32_t addr
= ufoPop();
5417 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5419 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
5420 &system
, &softinclude
);
5422 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5423 addr
= UFO_PAD_ADDR
+ 4u;
5425 while (ffn
[count
] != 0) {
5426 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)ffn
)[count
]);
5430 ufoImgPutU8Ext(addr
+ count
, 0);
5431 ufoImgPutU32(addr
- 4u, count
);
5436 // (INCLUDE-NO-REFILL)
5437 // ( addr count soft? system? -- )
5438 UFWORD(PAR_INCLUDE_NO_REFILL
) {
5439 uint32_t system
= ufoPop();
5440 uint32_t softinclude
= ufoPop();
5441 uint32_t count
= ufoPop();
5442 uint32_t addr
= ufoPop();
5444 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
5446 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5448 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
5449 &system
, &softinclude
);
5451 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5453 FILE *fl
= fopen(ffn
, "rb");
5455 FILE *fl
= fopen(ffn
, "r");
5458 if (softinclude
) { free(ffn
); return; }
5459 ufoFatal("include file '%s' not found", ffn
);
5461 #ifdef UFO_DEBUG_INCLUDE
5462 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
5467 ufoSetInFileNameReuse(ffn
);
5468 ufoFileId
= ufoLastUsedFileId
;
5469 setLastIncPath(ufoInFileName
, system
);
5474 UFWORD(PAR_INCLUDE_DROP
) {
5479 // ( addr count soft? system? -- )
5480 UFWORD(PAR_INCLUDE
) {
5481 UFCALL(PAR_INCLUDE_NO_REFILL
);
5482 // trigger next line loading
5484 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
5488 UFWORD(DLR_INCLUDE_IMM
) {
5489 int soft
= 0, system
= 0;
5490 // parse include filename
5491 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5492 uint8_t ch
= ufoTibPeekCh();
5494 ufoTibSkipCh(); // skip quote
5496 } else if (ch
== '<') {
5497 ufoTibSkipCh(); // skip quote
5501 ufoFatal("expected quoted string");
5504 if (!ufoPop()) ufoFatal("file name expected");
5505 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5506 if (ufoTibPeekCh() != 0) {
5507 ufoFatal("$INCLUDE doesn't accept extra args yet");
5509 // ( addr count soft? system? -- )
5510 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
5514 //==========================================================================
5516 // ufoCreateFileGuard
5518 //==========================================================================
5519 static const char *ufoCreateFileGuard (const char *fname
) {
5520 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
5521 char *rp
= ufoRealPath(fname
);
5522 if (rp
== NULL
) return NULL
;
5524 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
5526 // hash the buffer; extract file name; create string with path len, file name, and hash
5527 const size_t orgplen
= strlen(rp
);
5528 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
5529 size_t plen
= orgplen
;
5530 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
5531 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5532 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
5533 return ufoRealPathHashBuf
;
5537 // $INCLUDE-ONCE "str"
5538 // includes file only once; unreliable on shitdoze, i believe
5539 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
5540 uint32_t softinclude
= 0, system
= 0;
5541 // parse include filename
5542 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5543 uint8_t ch
= ufoTibPeekCh();
5545 ufoTibSkipCh(); // skip quote
5547 } else if (ch
== '<') {
5548 ufoTibSkipCh(); // skip quote
5552 ufoFatal("expected quoted string");
5555 if (!ufoPop()) ufoFatal("file name expected");
5556 const uint32_t count
= ufoPop();
5557 const uint32_t addr
= ufoPop();
5558 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5559 if (ufoTibPeekCh() != 0) {
5560 ufoFatal("$REQUIRE doesn't accept extra args yet");
5562 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5563 &system
, &softinclude
);
5564 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5565 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
5566 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5567 // this will overwrite `ufoRealPathHashBuf`
5568 const char *guard
= ufoCreateFileGuard(incfname
);
5570 if (guard
== NULL
) {
5571 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
5575 fprintf(stderr
, "GUARD: <%s>\n", guard
);
5577 // now check for the guard
5578 const uint32_t glen
= (uint32_t)strlen(guard
);
5579 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
5580 UForthCondDefine
*dd
;
5581 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5582 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
5583 // nothing to do: already included
5588 dd
= calloc(1, sizeof(UForthCondDefine
));
5589 if (dd
== NULL
) ufoFatal("out of memory for defines");
5590 dd
->name
= calloc(1, glen
+ 1u);
5591 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5592 strcpy(dd
->name
, guard
);
5595 dd
->next
= ufoCondDefines
;
5596 ufoCondDefines
= dd
;
5597 // ( addr count soft? system? -- )
5598 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
5599 UFCALL(PAR_INCLUDE
);
5603 // ////////////////////////////////////////////////////////////////////////// //
5609 UFWORD(PAR_NEW_HANDLE
) {
5610 const uint32_t typeid = ufoPop();
5611 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5612 UfoHandle
*hh
= ufoAllocHandle(typeid);
5613 ufoPush(hh
->ufoHandle
);
5618 UFWORD(PAR_FREE_HANDLE
) {
5619 const uint32_t hx
= ufoPop();
5621 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
5622 UfoHandle
*hh
= ufoGetHandle(hx
);
5623 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
5630 UFWORD(PAR_HANDLE_GET_TYPEID
) {
5631 const uint32_t hx
= ufoPop();
5632 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5633 UfoHandle
*hh
= ufoGetHandle(hx
);
5634 if (hh
== NULL
) ufoFatal("invalid handle");
5635 ufoPush(hh
->typeid);
5640 UFWORD(PAR_HANDLE_SET_TYPEID
) {
5641 const uint32_t hx
= ufoPop();
5642 const uint32_t typeid = ufoPop();
5643 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5644 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5645 UfoHandle
*hh
= ufoGetHandle(hx
);
5646 if (hh
== NULL
) ufoFatal("invalid handle");
5647 hh
->typeid = typeid;
5652 UFWORD(PAR_HANDLE_GET_SIZE
) {
5653 const uint32_t hx
= ufoPop();
5655 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5656 UfoHandle
*hh
= ufoGetHandle(hx
);
5657 if (hh
== NULL
) ufoFatal("invalid handle");
5666 UFWORD(PAR_HANDLE_SET_SIZE
) {
5667 const uint32_t hx
= ufoPop();
5668 const uint32_t size
= ufoPop();
5669 if (size
> 0x04000000) ufoFatal("invalid handle size");
5670 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5671 UfoHandle
*hh
= ufoGetHandle(hx
);
5672 if (hh
== NULL
) ufoFatal("invalid handle");
5673 if (hh
->size
!= size
) {
5678 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
5679 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
5681 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
5684 if (hh
->used
> size
) hh
->used
= size
;
5690 UFWORD(PAR_HANDLE_GET_USED
) {
5691 const uint32_t hx
= ufoPop();
5693 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5694 UfoHandle
*hh
= ufoGetHandle(hx
);
5695 if (hh
== NULL
) ufoFatal("invalid handle");
5704 UFWORD(PAR_HANDLE_SET_USED
) {
5705 const uint32_t hx
= ufoPop();
5706 const uint32_t used
= ufoPop();
5707 if (used
> 0x04000000) ufoFatal("invalid handle used");
5708 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5709 UfoHandle
*hh
= ufoGetHandle(hx
);
5710 if (hh
== NULL
) ufoFatal("invalid handle");
5711 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
5715 #define POP_PREPARE_HANDLE() \
5716 const uint32_t hx = ufoPop(); \
5717 uint32_t idx = ufoPop(); \
5718 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5719 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5720 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5721 UfoHandle *hh = ufoGetHandle(hx); \
5722 if (hh == NULL) ufoFatal("invalid handle")
5725 // ( idx hx -- value )
5726 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5727 POP_PREPARE_HANDLE();
5728 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5729 ufoPush(hh
->data
[idx
]);
5733 // ( idx hx -- value )
5734 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5735 POP_PREPARE_HANDLE();
5736 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5737 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5739 #ifdef UFO_FAST_MEM_ACCESS
5740 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5742 uint32_t res
= hh
->data
[idx
];
5743 res
|= hh
->data
[idx
+ 1u] << 8;
5749 // ( idx hx -- value )
5750 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5751 POP_PREPARE_HANDLE();
5752 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5753 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5755 #ifdef UFO_FAST_MEM_ACCESS
5756 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5758 uint32_t res
= hh
->data
[idx
];
5759 res
|= hh
->data
[idx
+ 1u] << 8;
5760 res
|= hh
->data
[idx
+ 2u] << 16;
5761 res
|= hh
->data
[idx
+ 3u] << 24;
5767 // ( value idx hx -- value )
5768 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5769 POP_PREPARE_HANDLE();
5770 const uint32_t value
= ufoPop();
5771 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5772 hh
->data
[idx
] = value
;
5776 // ( value idx hx -- )
5777 UFWORD(PAR_HANDLE_STORE_WORD
) {
5778 POP_PREPARE_HANDLE();
5779 const uint32_t value
= ufoPop();
5780 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5781 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5783 #ifdef UFO_FAST_MEM_ACCESS
5784 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5786 hh
->data
[idx
] = (uint8_t)value
;
5787 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5792 // ( value idx hx -- )
5793 UFWORD(PAR_HANDLE_STORE_CELL
) {
5794 POP_PREPARE_HANDLE();
5795 const uint32_t value
= ufoPop();
5796 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5797 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5799 #ifdef UFO_FAST_MEM_ACCESS
5800 *(uint32_t *)(hh
->data
+ idx
) = value
;
5802 hh
->data
[idx
] = (uint8_t)value
;
5803 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5804 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5805 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5811 // ( addr count -- stx / FALSE )
5812 UFWORD(PAR_HANDLE_LOAD_FILE
) {
5813 uint32_t count
= ufoPop();
5814 uint32_t addr
= ufoPop();
5816 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5818 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
5819 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
5820 uint8_t ch
= ufoImgGetU8Ext(addr
);
5822 dest
+= 1u; addr
+= 1u; count
-= 1u;
5824 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
5827 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
5829 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
5831 FILE *fl
= fopen(ffn
, "rb");
5833 FILE *fl
= fopen(ffn
, "r");
5841 if (fseek(fl
, 0, SEEK_END
) != 0) {
5843 ufoFatal("seek error in file '%s'", ffn
);
5846 long sz
= ftell(fl
);
5847 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
5849 ufoFatal("tell error in file '%s' (or too big)", ffn
);
5852 if (fseek(fl
, 0, SEEK_SET
) != 0) {
5854 ufoFatal("seek error in file '%s'", ffn
);
5857 UfoHandle
*hh
= ufoAllocHandle(0);
5859 hh
->data
= malloc((uint32_t)sz
);
5860 if (hh
->data
== NULL
) {
5862 ufoFatal("out of memory for file '%s'", ffn
);
5864 hh
->size
= (uint32_t)sz
;
5865 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
5867 ufoFatal("error reading file '%s'", ffn
);
5873 ufoPush(hh
->ufoHandle
);
5877 // ////////////////////////////////////////////////////////////////////////// //
5881 // DEBUG:(DECOMPILE-CFA)
5883 UFWORD(DEBUG_DECOMPILE_CFA
) {
5884 const uint32_t cfa
= ufoPop();
5886 ufoDecompileWord(cfa
);
5889 // DEBUG:(DECOMPILE-MEM)
5890 // ( addr-start addr-end -- )
5891 UFWORD(DEBUG_DECOMPILE_MEM
) {
5892 const uint32_t end
= ufoPop();
5893 const uint32_t start
= ufoPop();
5895 ufoDecompilePart(start
, end
, 0);
5901 ufoPush((uint32_t)ufo_get_msecs());
5904 // this is called by INTERPRET when it is out of input stream
5905 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
5911 UFWORD(MT_NEW_STATE
) {
5912 UfoState
*st
= ufoNewState();
5913 ufoInitStateUserVars(st
, ufoPop());
5919 UFWORD(MT_FREE_STATE
) {
5920 UfoState
*st
= ufoFindState(ufoPop());
5921 if (st
== NULL
) ufoFatal("cannot free unknown state");
5922 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5926 // MTASK:STATE-NAME@
5927 // ( stid -- addr count )
5929 UFWORD(MT_GET_STATE_NAME
) {
5930 UfoState
*st
= ufoFindState(ufoPop());
5931 if (st
== NULL
) ufoFatal("unknown state");
5933 uint32_t addr
= ufoPop();
5935 while (st
->name
[count
] != 0) {
5936 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5939 ufoImgPutU8Ext(addr
+ count
, 0);
5944 // MTASK:STATE-NAME!
5945 // ( addr count stid -- )
5946 UFWORD(MT_SET_STATE_NAME
) {
5947 UfoState
*st
= ufoFindState(ufoPop());
5948 if (st
== NULL
) ufoFatal("unknown state");
5949 uint32_t count
= ufoPop();
5950 uint32_t addr
= ufoPop();
5951 if ((count
& ((uint32_t)1 << 31)) == 0) {
5952 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5953 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5954 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5956 st
->name
[count
] = 0;
5960 // MTASK:STATE-FIRST
5962 UFWORD(MT_STATE_FIRST
) {
5964 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5965 // there should be at least one allocated state
5966 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5967 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5969 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5974 // ( stid -- stid / 0 )
5975 UFWORD(MT_STATE_NEXT
) {
5976 uint32_t stid
= ufoPop();
5977 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5978 // it is already incremented for us, yay!
5979 uint32_t fidx
= stid
/ 32u;
5980 uint8_t fofs
= stid
& 0x1f;
5981 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5982 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5984 while (fofs
!= 32u) {
5985 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5988 ufoPush(fidx
* 32u + fofs
+ 1u);
5992 fidx
+= 1u; fofs
= 0;
6000 // ( ... argc stid -- )
6001 UFWORD(MT_YIELD_TO
) {
6002 UfoState
*st
= ufoFindState(ufoPop());
6003 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
6004 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
6005 const uint32_t argc
= ufoPop();
6006 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
6007 UfoState
*curst
= ufoCurrState
;
6008 if (st
!= ufoCurrState
) {
6009 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
6010 ufoCurrState
= curst
;
6011 const uint32_t n
= ufoPop();
6015 ufoCurrState
= curst
; // we need to use API call to switch states
6017 ufoSwitchToState(st
); // always use API call for this!
6022 // MTASK:SET-SELF-AS-DEBUGGER
6024 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
6025 ufoDebuggerState
= ufoCurrState
;
6030 // debugger task receives debugge stid on the data stack, and -1 as argc.
6031 // i.e. debugger stask is: ( -1 old-stid )
6032 UFWORD(MT_DEBUGGER_BP
) {
6033 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
&& ufoIsGoodTTY()) {
6034 UfoState
*st
= ufoCurrState
;
6035 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
6040 UFCALL(UFO_BACKTRACE
);
6044 // MTASK:DEBUGGER-RESUME
6046 UFWORD(MT_RESUME_DEBUGEE
) {
6047 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
6048 UfoState
*st
= ufoFindState(ufoPop());
6049 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
6050 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
6051 ufoSwitchToState(st
); // always use API call for this!
6055 // MTASK:DEBUGGER-SINGLE-STEP
6057 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
6058 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
6059 UfoState
*st
= ufoFindState(ufoPop());
6060 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
6061 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
6062 ufoSwitchToState(st
); // always use API call for this!
6063 ufoSingleStep
= 2; // it will be decremented after returning from this word
6068 UFWORD(MT_STATE_IP_GET
) {
6069 UfoState
*st
= ufoFindState(ufoPop());
6070 if (st
== NULL
) ufoFatal("unknown state");
6076 UFWORD(MT_STATE_IP_SET
) {
6077 UfoState
*st
= ufoFindState(ufoPop());
6078 if (st
== NULL
) ufoFatal("unknown state");
6084 UFWORD(MT_STATE_REGA_GET
) {
6085 UfoState
*st
= ufoFindState(ufoPop());
6086 if (st
== NULL
) ufoFatal("unknown state");
6092 UFWORD(MT_STATE_REGA_SET
) {
6093 UfoState
*st
= ufoFindState(ufoPop());
6094 if (st
== NULL
) ufoFatal("unknown state");
6095 st
->regA
= ufoPop();
6098 // MTASK:STATE-USER@
6099 // ( addr stid -- value )
6100 UFWORD(MT_STATE_USER_GET
) {
6101 UfoState
*st
= ufoFindState(ufoPop());
6102 if (st
== NULL
) ufoFatal("unknown state");
6103 const uint32_t addr
= ufoPop();
6104 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
6105 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
6108 ufoFatal("invalid user area address");
6112 // MTASK:STATE-USER!
6113 // ( value addr stid -- )
6114 UFWORD(MT_STATE_USER_SET
) {
6115 UfoState
*st
= ufoFindState(ufoPop());
6116 if (st
== NULL
) ufoFatal("unknown state");
6117 const uint32_t addr
= ufoPop();
6118 const uint32_t value
= ufoPop();
6119 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
6120 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
6122 ufoFatal("invalid user area address");
6126 // MTASK:STATE-RPOPCFA@
6128 UFWORD(MT_STATE_RPOPCFA_GET
) {
6129 UfoState
*st
= ufoFindState(ufoPop());
6130 if (st
== NULL
) ufoFatal("unknown state");
6131 ufoPush(st
->vmRPopCFA
);
6134 // MTASK:STATE-RPOPCFA!
6136 UFWORD(MT_STATE_RPOPCFA_SET
) {
6137 UfoState
*st
= ufoFindState(ufoPop());
6138 if (st
== NULL
) ufoFatal("unknown state");
6139 st
->vmRPopCFA
= ufoPop();
6142 // MTASK:ACTIVE-STATE
6144 UFWORD(MT_ACTIVE_STATE
) {
6145 ufoPush(ufoCurrState
->id
);
6148 // MTASK:YIELDED-FROM
6150 UFWORD(MT_YIELDED_FROM
) {
6151 if (ufoYieldedState
!= NULL
) {
6152 ufoPush(ufoYieldedState
->id
);
6159 // ( stid -- depth )
6160 UFWORD(MT_DSTACK_DEPTH_GET
) {
6161 UfoState
*st
= ufoFindState(ufoPop());
6162 if (st
== NULL
) ufoFatal("unknown state");
6167 // ( stid -- depth )
6168 UFWORD(MT_RSTACK_DEPTH_GET
) {
6169 UfoState
*st
= ufoFindState(ufoPop());
6170 if (st
== NULL
) ufoFatal("unknown state");
6171 ufoPush(st
->RP
- st
->RPTop
);
6177 UfoState
*st
= ufoFindState(ufoPop());
6178 if (st
== NULL
) ufoFatal("unknown state");
6184 UFWORD(MT_LBP_GET
) {
6185 UfoState
*st
= ufoFindState(ufoPop());
6186 if (st
== NULL
) ufoFatal("unknown state");
6191 // ( depth stid -- )
6192 UFWORD(MT_DSTACK_DEPTH_SET
) {
6193 UfoState
*st
= ufoFindState(ufoPop());
6194 if (st
== NULL
) ufoFatal("unknown state");
6195 const uint32_t idx
= ufoPop();
6196 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
6201 // ( depth stid -- )
6202 UFWORD(MT_RSTACK_DEPTH_SET
) {
6203 UfoState
*st
= ufoFindState(ufoPop());
6204 if (st
== NULL
) ufoFatal("unknown state");
6205 const uint32_t idx
= ufoPop();
6206 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
6207 if (idx
>= left
) ufoFatal("invalid rstack index %u (%u)", idx
, left
);
6208 st
->RP
= st
->RPTop
+ idx
;
6214 UfoState
*st
= ufoFindState(ufoPop());
6215 if (st
== NULL
) ufoFatal("unknown state");
6221 UFWORD(MT_LBP_SET
) {
6222 UfoState
*st
= ufoFindState(ufoPop());
6223 if (st
== NULL
) ufoFatal("unknown state");
6228 // ( idx stid -- value )
6229 UFWORD(MT_DSTACK_LOAD
) {
6230 UfoState
*st
= ufoFindState(ufoPop());
6231 if (st
== NULL
) ufoFatal("unknown state");
6232 const uint32_t idx
= ufoPop();
6233 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6234 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
6238 // ( idx stid -- value )
6239 UFWORD(MT_RSTACK_LOAD
) {
6240 UfoState
*st
= ufoFindState(ufoPop());
6241 if (st
== NULL
) ufoFatal("unknown state");
6242 const uint32_t idx
= ufoPop();
6243 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6244 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
6248 // ( idx stid -- value )
6249 UFWORD(MT_LSTACK_LOAD
) {
6250 UfoState
*st
= ufoFindState(ufoPop());
6251 if (st
== NULL
) ufoFatal("unknown state");
6252 const uint32_t idx
= ufoPop();
6253 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
6254 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
6258 // ( value idx stid -- )
6259 UFWORD(MT_DSTACK_STORE
) {
6260 UfoState
*st
= ufoFindState(ufoPop());
6261 if (st
== NULL
) ufoFatal("unknown state");
6262 const uint32_t idx
= ufoPop();
6263 const uint32_t value
= ufoPop();
6264 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
6265 st
->dStack
[st
->SP
- idx
- 1u] = value
;
6269 // ( value idx stid -- )
6270 UFWORD(MT_RSTACK_STORE
) {
6271 UfoState
*st
= ufoFindState(ufoPop());
6272 if (st
== NULL
) ufoFatal("unknown state");
6273 const uint32_t idx
= ufoPop();
6274 const uint32_t value
= ufoPop();
6275 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
6276 st
->dStack
[st
->RP
- idx
- 1u] = value
;
6280 // ( value idx stid -- )
6281 UFWORD(MT_LSTACK_STORE
) {
6282 UfoState
*st
= ufoFindState(ufoPop());
6283 if (st
== NULL
) ufoFatal("unknown state");
6284 const uint32_t idx
= ufoPop();
6285 const uint32_t value
= ufoPop();
6286 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
6287 st
->dStack
[st
->LP
- idx
- 1u] = value
;
6292 UFWORD(MT_VSP_GET
) {
6293 UfoState
*st
= ufoFindState(ufoPop());
6294 if (st
== NULL
) ufoFatal("unknown state");
6300 UFWORD(MT_VSP_SET
) {
6301 UfoState
*st
= ufoFindState(ufoPop());
6302 if (st
== NULL
) ufoFatal("unknown state");
6303 const uint32_t vsp
= ufoPop();
6304 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6308 // MTASK:STATE-VSP-AT@
6309 // ( idx stidf -- value )
6310 UFWORD(MT_VSP_LOAD
) {
6311 UfoState
*st
= ufoFindState(ufoPop());
6312 if (st
== NULL
) ufoFatal("unknown state");
6313 const uint32_t vsp
= ufoPop();
6314 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6315 ufoPush(st
->vocStack
[vsp
]);
6318 // MTASK:STATE-VSP-AT!
6319 // ( value idx stid -- )
6320 UFWORD(MT_VSP_STORE
) {
6321 UfoState
*st
= ufoFindState(ufoPop());
6322 if (st
== NULL
) ufoFatal("unknown state");
6323 const uint32_t vsp
= ufoPop();
6324 const uint32_t value
= ufoPop();
6325 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6326 st
->vocStack
[vsp
] = value
;
6330 #include "urforth_tty.c"
6333 // ////////////////////////////////////////////////////////////////////////// //
6337 static unsigned char ufoFileIOBuffer
[4096];
6340 //==========================================================================
6344 //==========================================================================
6345 static char *ufoPopFileName (void) {
6346 uint32_t count
= ufoPop();
6347 uint32_t addr
= ufoPop();
6349 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid file name");
6350 if (count
== 0) ufoFatal("empty file name");
6351 if (count
> (uint32_t)sizeof(ufoFNameBuf
) - 1u) ufoFatal("file name too long");
6353 unsigned char *dest
= (unsigned char *)ufoFNameBuf
;
6354 while (count
!= 0) {
6355 *dest
= ufoImgGetU8Ext(addr
);
6356 dest
+= 1u; addr
+= 1u; count
-= 1u;
6365 UFWORD(FILES_ERRNO
) {
6366 ufoPush((uint32_t)errno
);
6370 // ( addr count -- success? )
6371 UFWORD(FILES_UNLINK
) {
6372 const char *fname
= ufoPopFileName();
6373 ufoPushBool(unlink(fname
) == 0);
6377 // ( addr count -- handle TRUE / FALSE )
6378 UFWORD(FILES_OPEN_RO
) {
6379 const char *fname
= ufoPopFileName();
6380 const int fd
= open(fname
, O_RDONLY
);
6382 ufoPush((uint32_t)fd
);
6390 // ( addr count -- handle TRUE / FALSE )
6391 UFWORD(FILES_OPEN_RW
) {
6392 const char *fname
= ufoPopFileName();
6393 const int fd
= open(fname
, O_RDWR
);
6395 ufoPush((uint32_t)fd
);
6403 // ( addr count -- handle TRUE / FALSE )
6404 UFWORD(FILES_CREATE
) {
6405 const char *fname
= ufoPopFileName();
6406 //FIXME: add variable with default flags
6407 const int fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6409 ufoPush((uint32_t)fd
);
6417 // ( handle -- success? )
6418 UFWORD(FILES_CLOSE
) {
6419 const int32_t fd
= (int32_t)ufoPop();
6420 if (fd
< 0) ufoFatal("invalid file handle in 'CLOSE'");
6421 ufoPushBool(close(fd
) == 0);
6425 // ( handle -- ofs TRUE / FALSE )
6426 // `handle` cannot be 0.
6427 UFWORD(FILES_TELL
) {
6428 const int32_t fd
= (int32_t)ufoPop();
6429 if (fd
< 0) ufoFatal("invalid file handle in 'TELL'");
6430 const off_t pos
= lseek(fd
, 0, SEEK_CUR
);
6431 if (pos
!= (off_t
)-1) {
6432 ufoPush((uint32_t)pos
);
6440 // ( ofs whence handle -- TRUE / FALSE )
6441 // `handle` cannot be 0.
6442 UFWORD(FILES_SEEK_EX
) {
6443 const int32_t fd
= (int32_t)ufoPop();
6444 const uint32_t whence
= ufoPop();
6445 const uint32_t ofs
= ufoPop();
6446 if (fd
< 0) ufoFatal("invalid file handle in 'SEEK-EX'");
6447 if (whence
!= (uint32_t)SEEK_SET
&&
6448 whence
!= (uint32_t)SEEK_CUR
&&
6449 whence
!= (uint32_t)SEEK_END
) ufoFatal("invalid `whence` in 'SEEK-EX'");
6450 const off_t pos
= lseek(fd
, (off_t
)ofs
, (int)whence
);
6451 ufoPushBool(pos
!= (off_t
)-1);
6455 // ( handle -- size TRUE / FALSE )
6456 // `handle` cannot be 0.
6457 UFWORD(FILES_SIZE
) {
6458 const int32_t fd
= (int32_t)ufoPop();
6459 if (fd
< 0) ufoFatal("invalid file handle in 'SIZE'");
6460 const off_t origpos
= lseek(fd
, 0, SEEK_CUR
);
6461 if (origpos
== (off_t
)-1) {
6464 const off_t size
= lseek(fd
, 0, SEEK_END
);
6465 if (size
== (off_t
)-1) {
6466 (void)lseek(origpos
, 0, SEEK_SET
);
6468 } else if (lseek(origpos
, 0, SEEK_SET
) == origpos
) {
6469 ufoPush((uint32_t)size
);
6478 // ( addr count handle -- rdsize TRUE / FALSE )
6479 // `handle` cannot be 0.
6480 UFWORD(FILES_READ
) {
6481 const int32_t fd
= (int32_t)ufoPop();
6482 if (fd
< 0) ufoFatal("invalid file handle in 'READ'");
6483 uint32_t count
= ufoPop();
6484 uint32_t addr
= ufoPop();
6487 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6488 while (count
!= done
) {
6489 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6490 if (rd
> count
) rd
= count
;
6492 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6493 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6494 if (errno
== EINTR
) continue;
6495 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6502 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6503 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6513 // ( addr count handle -- TRUE / FALSE )
6514 // `handle` cannot be 0.
6515 UFWORD(FILES_READ_EXACT
) {
6516 const int32_t fd
= (int32_t)ufoPop();
6517 if (fd
< 0) ufoFatal("invalid file handle in 'READ-EXACT'");
6518 uint32_t count
= ufoPop();
6519 uint32_t addr
= ufoPop();
6521 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
6522 while (count
!= 0) {
6523 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
6524 if (rd
> count
) rd
= count
;
6526 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
6527 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
6528 if (errno
== EINTR
) continue;
6529 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
6534 if (rd
== 0) { ufoPushBool(0); return; } // still error
6536 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
6537 ufoImgPutU8Ext(addr
, ufoFileIOBuffer
[f
]);
6546 // ( addr count handle -- TRUE / FALSE )
6547 // `handle` cannot be 0.
6548 UFWORD(FILES_WRITE
) {
6549 const int32_t fd
= (int32_t)ufoPop();
6550 if (fd
< 0) ufoFatal("invalid file handle in 'WRITE'");
6551 uint32_t count
= ufoPop();
6552 uint32_t addr
= ufoPop();
6554 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to write to file");
6555 while (count
!= 0) {
6556 uint32_t wr
= (uint32_t)sizeof(ufoFileIOBuffer
);
6557 if (wr
> count
) wr
= count
;
6558 for (uint32_t f
= 0; f
!= wr
; f
+= 1u) {
6559 ufoFileIOBuffer
[f
] = ufoImgGetU8Ext(addr
+ f
);
6562 const ssize_t xres
= write(fd
, ufoFileIOBuffer
, wr
);
6563 if (xres
>= 0) { wr
= (uint32_t)xres
; break; }
6564 if (errno
== EINTR
) continue;
6565 fprintf(stderr
, "ERRNO: %d (fd=%d)\n", errno
, fd
);
6566 //if (errno == EAGAIN || errno == EWOULDBLOCK) { wr = 0; break; }
6571 if (wr
== 0) { ufoPushBool(1); return; } // still error
6572 count
-= wr
; addr
+= wr
;
6579 // ////////////////////////////////////////////////////////////////////////// //
6583 //==========================================================================
6587 // create a new state, its execution will start from the given CFA.
6588 // state is not automatically activated.
6590 //==========================================================================
6591 static UfoState
*ufoNewState (void) {
6592 // find free state id
6594 uint32_t bmp
= ufoStateUsedBitmap
[0];
6595 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
6597 bmp
= ufoStateUsedBitmap
[fidx
];
6599 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
6600 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6602 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
6603 ufo_assert(fidx
< UFO_MAX_STATES
);
6604 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
6605 ufo_assert(ufoStateMap
[fidx
] == NULL
);
6606 UfoState
*st
= calloc(1, sizeof(UfoState
));
6607 if (st
== NULL
) ufoFatal("out of memory for states");
6609 ufoStateMap
[fidx
] = st
;
6610 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
6611 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6616 //==========================================================================
6620 // free all memory used for the state, remove it from state list.
6621 // WARNING! never free current state!
6623 //==========================================================================
6624 static void ufoFreeState (UfoState
*st
) {
6626 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
6627 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
6628 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
6629 const uint32_t fidx
= st
->id
- 1u;
6630 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6631 ufo_assert(fidx
< UFO_MAX_STATES
);
6632 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
6633 ufo_assert(ufoStateMap
[fidx
] == st
);
6634 // free default TIB handle
6635 UfoState
*oldst
= ufoCurrState
;
6637 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
6638 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
6639 UfoHandle
*tibh
= ufoGetHandle(tib
);
6640 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
6642 ufoCurrState
= oldst
;
6644 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
6646 ufoStateMap
[fidx
] = NULL
;
6647 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
6652 //==========================================================================
6656 //==========================================================================
6657 static UfoState
*ufoFindState (uint32_t stid
) {
6658 UfoState
*res
= NULL
;
6659 if (stid
>= 0 && stid
<= UFO_MAX_STATES
) {
6662 ufo_assert(ufoCurrState
!= NULL
);
6663 stid
= ufoCurrState
->id
- 1u;
6667 res
= ufoStateMap
[stid
];
6669 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
6670 ufo_assert(res
->id
== stid
+ 1u);
6672 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
6679 //==========================================================================
6683 //==========================================================================
6684 static void ufoSwitchToState (UfoState
*newst
) {
6685 ufo_assert(newst
!= NULL
);
6686 if (newst
!= ufoCurrState
) {
6687 ufoCurrState
= newst
;
6692 // ////////////////////////////////////////////////////////////////////////// //
6693 // initial dictionary definitions
6698 #define UFWORD(name_) do { \
6699 const uint32_t xcfa_ = ufoCFAsUsed; \
6700 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6701 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6703 ufoDefineNative(""#name_, xcfa_, 0); \
6706 #define UFWORDX(strname_,name_) do { \
6707 const uint32_t xcfa_ = ufoCFAsUsed; \
6708 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6709 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6711 ufoDefineNative(strname_, xcfa_, 0); \
6714 #define UFWORD_IMM(name_) do { \
6715 const uint32_t xcfa_ = ufoCFAsUsed; \
6716 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6717 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6719 ufoDefineNative(""#name_, xcfa_, 1); \
6722 #define UFWORDX_IMM(strname_,name_) do { \
6723 const uint32_t xcfa_ = ufoCFAsUsed; \
6724 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6725 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6727 ufoDefineNative(strname_, xcfa_, 1); \
6730 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
6733 //==========================================================================
6735 // ufoFindWordChecked
6737 //==========================================================================
6738 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
6739 const uint32_t cfa
= ufoFindWord(wname
);
6740 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
6745 //==========================================================================
6749 // get "FORTH" vocid
6751 //==========================================================================
6752 uint32_t ufoGetForthVocId (void) {
6753 return ufoForthVocId
;
6757 //==========================================================================
6759 // ufoVocSetOnlyDefs
6761 //==========================================================================
6762 void ufoVocSetOnlyDefs (uint32_t vocid
) {
6763 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6764 ufoImgPutU32(ufoAddrContext
, vocid
);
6768 //==========================================================================
6772 // return voc PFA (vocid)
6774 //==========================================================================
6775 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
6776 // create wordlist struct
6777 // typeid, used by Forth code (structs and such)
6778 ufoImgEmitU32(0); // typeid
6779 // vocid points here, to "LATEST-LFA"
6780 const uint32_t vocid
= UFO_GET_DP();
6781 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
6782 ufoImgEmitU32(0); // latest
6783 const uint32_t vlink
= UFO_GET_DP();
6784 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
6785 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
6786 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
6791 ufoImgEmitU32(parentvocid
); // parent
6792 const uint32_t hdraddr
= UFO_GET_DP();
6793 ufoImgEmitU32(0); // word header
6794 // create empty hash table
6795 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
6796 // update CONTEXT and CURRENT if this is the first wordlist ever
6797 if (ufoImgGetU32(ufoAddrContext
) == 0) {
6798 ufoImgPutU32(ufoAddrContext
, vocid
);
6800 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
6801 ufoImgPutU32(ufoAddrCurrent
, vocid
);
6803 // create word header
6804 if (wname
!= NULL
&& wname
[0] != 0) {
6806 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6808 //UFW_FLAG_IMMEDIATE|
6810 //UFW_FLAG_NORETURN|
6816 flags |= UFW_FLAG_VOCAB;
6818 flags
&= 0xffffff00u
;
6819 flags
|= UFW_FLAG_VOCAB
;
6820 ufoCreateWordHeader(wname
, flags
);
6821 const uint32_t cfa
= UFO_GET_DP();
6822 ufoImgEmitU32(ufoDoVocCFA
); // cfa
6823 ufoImgEmitU32(vocid
); // pfa
6824 // update vocab header pointer
6825 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
6826 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
6827 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6828 ufoDumpWordHeader(lfa
);
6835 //==========================================================================
6839 //==========================================================================
6840 static void ufoSetLatestArgs (uint32_t warg
) {
6841 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
6842 const uint32_t lfa
= ufoImgGetU32(curr
);
6843 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
6844 uint32_t flags
= ufoImgGetU32(nfa
);
6845 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
6846 flags
&= ~UFW_WARG_MASK
;
6847 flags
|= warg
& UFW_WARG_MASK
;
6848 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
6849 ufoImgPutU32(nfa
, flags
);
6850 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6851 ufoDumpWordHeader(lfa
);
6856 //==========================================================================
6860 //==========================================================================
6861 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
6862 cfaidx
|= UFO_ADDR_CFA_BIT
;
6863 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6865 //UFW_FLAG_IMMEDIATE|
6867 //UFW_FLAG_NORETURN|
6873 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
6874 ufoCreateWordHeader(wname
, flags
);
6875 ufoImgEmitU32(cfaidx
);
6879 //==========================================================================
6881 // ufoDefineConstant
6883 //==========================================================================
6884 static void ufoDefineConstant (const char *name
, uint32_t value
) {
6885 ufoDefineNative(name
, ufoDoConstCFA
, 0);
6886 ufoImgEmitU32(value
);
6890 //==========================================================================
6894 //==========================================================================
6895 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
6896 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
6897 ufoImgEmitU32(addr
);
6901 //==========================================================================
6905 //==========================================================================
6907 static void ufoDefineVar (const char *name, uint32_t value) {
6908 ufoDefineNative(name, ufoDoVarCFA, 0);
6909 ufoImgEmitU32(value);
6914 //==========================================================================
6918 //==========================================================================
6920 static void ufoDefineDefer (const char *name, uint32_t value) {
6921 ufoDefineNative(name, ufoDoDeferCFA, 0);
6922 ufoImgEmitU32(value);
6927 //==========================================================================
6931 //==========================================================================
6932 static void ufoHiddenWords (void) {
6933 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6934 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6938 //==========================================================================
6942 //==========================================================================
6943 static void ufoPublicWords (void) {
6944 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6945 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
6949 //==========================================================================
6953 //==========================================================================
6955 static void ufoDefineForth (const char *name) {
6956 ufoDefineNative(name, ufoDoForthCFA, 0);
6961 //==========================================================================
6963 // ufoDefineForthImm
6965 //==========================================================================
6967 static void ufoDefineForthImm (const char *name) {
6968 ufoDefineNative(name, ufoDoForthCFA, 1);
6973 //==========================================================================
6975 // ufoDefineForthHidden
6977 //==========================================================================
6979 static void ufoDefineForthHidden (const char *name) {
6980 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6981 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6982 ufoDefineNative(name, ufoDoForthCFA, 0);
6983 ufoImgPutU32(ufoAddrNewWordFlags, flags);
6988 //==========================================================================
6990 // ufoDefineSColonForth
6992 // create word suitable for scattered colon extension
6994 //==========================================================================
6995 static void ufoDefineSColonForth (const char *name
) {
6996 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6997 // placeholder for scattered colon
6998 // it will compile two branches:
6999 // the first branch will jump to the first "..:" word (or over the two branches)
7000 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
7001 // this way, each extension word will simply fix the last branch address, and update list tail
7002 // at the creation time, second branch points to the first branch
7003 UFC("FORTH:(BRANCH)");
7004 const uint32_t xjmp
= UFO_GET_DP();
7006 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
7007 ufoImgPutU32(xjmp
, UFO_GET_DP());
7011 //==========================================================================
7015 //==========================================================================
7016 UFO_FORCE_INLINE
void ufoDoneForth (void) {
7017 UFC("FORTH:(EXIT)");
7021 //==========================================================================
7025 // compile string literal, the same as QUOTE_IMM
7027 //==========================================================================
7028 static void ufoCompileStrLitEx (const char *str
, const uint32_t slen
) {
7029 if (str
== NULL
) str
= "";
7030 if (slen
> 255) ufoFatal("string literal too long");
7031 UFC("FORTH:(LITSTR8)");
7032 ufoImgEmitU8((uint8_t)slen
);
7033 for (size_t f
= 0; f
< slen
; f
+= 1) {
7034 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
7041 //==========================================================================
7045 //==========================================================================
7047 static void ufoCompileStrLit (const char *str) {
7048 ufoCompileStrLitEx(str, (uint32_t)strlen(str));
7053 //==========================================================================
7057 //==========================================================================
7058 static void ufoCompileLit (uint32_t value
) {
7060 ufoImgEmitU32(value
);
7064 //==========================================================================
7068 //==========================================================================
7070 static void ufoCompileCFALit (const char *wname) {
7071 UFC("FORTH:(LITCFA)");
7072 const uint32_t cfa = ufoFindWordChecked(wname);
7078 //==========================================================================
7082 //==========================================================================
7083 static int ufoXStrEquCI (const char *word
, const char *text
, uint32_t tlen
) {
7084 while (tlen
!= 0 && *word
) {
7085 if (toUpper(*word
) != toUpper(*text
)) return 0;
7086 word
+= 1u; text
+= 1u; tlen
-= 1u;
7088 return (tlen
== 0 && *word
== 0);
7092 #define UFO_MAX_LABEL_NAME (63)
7093 typedef struct UfoLabel_t
{
7096 char name
[UFO_MAX_LABEL_NAME
];
7097 uint32_t addr
; // jump chain tail, or address
7099 uint32_t word
; // is this a forward word definition?
7100 struct UfoLabel_t
*next
;
7103 static UfoLabel
*ufoLabels
= NULL
;
7106 //==========================================================================
7108 // ufoFindAddLabelEx
7110 //==========================================================================
7111 static UfoLabel
*ufoFindAddLabelEx (const char *name
, uint32_t namelen
, int allowAdd
) {
7112 if (namelen
== 0 || namelen
> UFO_MAX_LABEL_NAME
) ufoFatal("invalid label name");
7113 const uint32_t hash
= joaatHashBufCI(name
, namelen
);
7114 UfoLabel
*lbl
= ufoLabels
;
7115 while (lbl
!= NULL
) {
7116 if (lbl
->hash
== hash
&& lbl
->namelen
== namelen
) {
7119 while (ok
&& sidx
!= namelen
) {
7120 ok
= (toUpper(name
[sidx
]) == toUpper(lbl
->name
[sidx
]));
7129 lbl
= calloc(1, sizeof(UfoLabel
));
7131 lbl
->namelen
= namelen
;
7132 memcpy(lbl
->name
, name
, namelen
);
7133 lbl
->name
[namelen
] = 0;
7134 lbl
->next
= ufoLabels
;
7143 //==========================================================================
7147 //==========================================================================
7148 static UfoLabel
*ufoFindAddLabel (const char *name
, uint32_t namelen
) {
7149 return ufoFindAddLabelEx(name
, namelen
, 1);
7153 //==========================================================================
7157 //==========================================================================
7158 static UfoLabel
*ufoFindLabel (const char *name
, uint32_t namelen
) {
7159 return ufoFindAddLabelEx(name
, namelen
, 0);
7163 //==========================================================================
7165 // ufoTrySimpleNumber
7167 // only decimal and C-like hexes; with an optional sign
7169 //==========================================================================
7170 static int ufoTrySimpleNumber (const char *text
, uint32_t tlen
, uint32_t *num
) {
7173 if (tlen
!= 0 && *text
== '+') { text
+= 1u; tlen
-= 1u; }
7174 else if (tlen
!= 0 && *text
== '-') { neg
= 1; text
+= 1u; tlen
-= 1u; }
7176 int base
= 10; // default base
7177 if (tlen
> 2 && text
[0] == '0' && toUpper(text
[1]) == 'X') {
7180 text
+= 2u; tlen
-= 2u;
7183 if (tlen
== 0 || digitInBase(*text
, base
) < 0) return 0;
7190 if (!wasDigit
) return 0;
7193 dig
= digitInBase(*text
, base
);
7194 if (dig
< 0) return 0;
7196 n
= n
* (uint32_t)base
+ (uint32_t)dig
;
7198 text
+= 1u; tlen
-= 1u;
7201 if (!wasDigit
) return 0;
7202 if (neg
) n
= ~n
+ 1u;
7208 //==========================================================================
7210 // ufoEmitLabelChain
7212 //==========================================================================
7213 static void ufoEmitLabelChain (UfoLabel
*lbl
) {
7214 ufo_assert(lbl
!= NULL
);
7215 ufo_assert(lbl
->defined
== 0);
7216 const uint32_t here
= UFO_GET_DP();
7217 ufoImgEmitU32(lbl
->addr
);
7222 //==========================================================================
7224 // ufoFixLabelChainHere
7226 //==========================================================================
7227 static void ufoFixLabelChainHere (UfoLabel
*lbl
) {
7228 ufo_assert(lbl
!= NULL
);
7229 ufo_assert(lbl
->defined
== 0);
7230 const uint32_t here
= UFO_GET_DP();
7231 while (lbl
->addr
!= 0) {
7232 const uint32_t aprev
= ufoImgGetU32(lbl
->addr
);
7233 ufoImgPutU32(lbl
->addr
, here
);
7241 #define UFO_MII_WORD_COMPILE_IMM (-4)
7242 #define UFO_MII_WORD_CFA_LIT (-3)
7243 #define UFO_MII_WORD_COMPILE (-2)
7244 #define UFO_MII_IN_WORD (-1)
7245 #define UFO_MII_NO_WORD (0)
7246 #define UFO_MII_WORD_NAME (1)
7247 #define UFO_MII_WORD_NAME_IMM (2)
7248 #define UFO_MII_WORD_NAME_HIDDEN (3)
7250 static int ufoMinInterpState
= UFO_MII_NO_WORD
;
7253 //==========================================================================
7255 // ufoFinalLabelCheck
7257 //==========================================================================
7258 static void ufoFinalLabelCheck (void) {
7260 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) {
7261 ufoFatal("missing semicolon");
7263 while (ufoLabels
!= NULL
) {
7264 UfoLabel
*lbl
= ufoLabels
; ufoLabels
= lbl
->next
;
7265 if (!lbl
->defined
) {
7266 fprintf(stderr
, "UFO ERROR: label '%s' is not defined!\n", lbl
->name
);
7271 if (errorCount
!= 0) {
7272 ufoFatal("%d undefined label%s", errorCount
, (errorCount
!= 1 ? "s" : ""));
7277 //==========================================================================
7281 // this is so i could write Forth definitions more easily
7284 // $name -- reference
7285 // $name: -- definition
7287 //==========================================================================
7288 UFO_DISABLE_INLINE
void ufoInterpretLine (const char *line
) {
7289 char wname
[UFO_MAX_WORD_LENGTH
];
7290 uint32_t wlen
, num
, cfa
;
7293 if (*(const unsigned char *)line
<= 32) {
7295 } else if (ufoMinInterpState
== UFO_MII_WORD_CFA_LIT
||
7296 ufoMinInterpState
== UFO_MII_WORD_COMPILE
||
7297 ufoMinInterpState
== UFO_MII_WORD_COMPILE_IMM
)
7299 // "[']"/"COMPILE"/"[COMPILE]" argument
7301 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7302 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7303 memcpy(wname
, line
, wlen
);
7305 switch (ufoMinInterpState
) {
7306 case UFO_MII_WORD_CFA_LIT
: UFC("FORTH:(LITCFA)"); break;
7307 case UFO_MII_WORD_COMPILE
: UFC("FORTH:(LITCFA)"); break;
7308 case UFO_MII_WORD_COMPILE_IMM
: break;
7309 default: ufo_assert(0);
7311 cfa
= ufoFindWord(wname
);
7315 // forward reference
7316 lbl
= ufoFindAddLabel(line
, wlen
);
7317 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7318 ufoFatal("unknown word: '%s'", wname
);
7321 ufoEmitLabelChain(lbl
);
7323 switch (ufoMinInterpState
) {
7324 case UFO_MII_WORD_CFA_LIT
: break;
7325 case UFO_MII_WORD_COMPILE
: UFC("FORTH:COMPILE,"); break;
7326 case UFO_MII_WORD_COMPILE_IMM
: break;
7327 default: ufo_assert(0);
7329 ufoMinInterpState
= UFO_MII_IN_WORD
;
7331 } else if (ufoMinInterpState
> UFO_MII_NO_WORD
) {
7334 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7335 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7336 if (wlen
> 2 && line
[0] == ':' && line
[wlen
- 1u] == ':') ufoFatal("invalid word name");
7337 memcpy(wname
, line
, wlen
);
7339 const uint32_t oldFlags
= ufoImgGetU32(ufoAddrNewWordFlags
);
7340 if (ufoMinInterpState
== UFO_MII_WORD_NAME_HIDDEN
) {
7341 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
| UFW_FLAG_HIDDEN
);
7343 ufoDefineNative(wname
, ufoDoForthCFA
, (ufoMinInterpState
== UFO_MII_WORD_NAME_IMM
));
7344 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
);
7345 ufoMinInterpState
= UFO_MII_IN_WORD
;
7346 // check for forward references
7347 lbl
= ufoFindLabel(line
, wlen
);
7349 if (lbl
->defined
|| !lbl
->word
) {
7350 ufoFatal("label/word conflict for '%.*s'", (unsigned)wlen
, line
);
7352 ufoFixLabelChainHere(lbl
);
7355 } else if ((line
[0] == ';' && line
[1] == ';') ||
7356 (line
[0] == '-' && line
[1] == '-') ||
7357 (line
[0] == '/' && line
[1] == '/') ||
7358 (line
[0] == '\\' && ((const unsigned char *)line
)[1] <= 32))
7360 ufoFatal("do not use single-line comments");
7361 } else if (line
[0] == '(' && ((const unsigned char *)line
)[1] <= 32) {
7362 while (*line
&& *line
!= ')') line
+= 1;
7363 if (*line
== ')') line
+= 1;
7367 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
7368 if (wlen
== 1 && (line
[0] == '"' || line
[0] == '`')) {
7370 const char qch
= line
[0];
7371 if (!line
[1]) ufoFatal("unterminated string literal");
7372 // skip quote and space
7373 if (((const unsigned char *)line
)[1] <= 32) line
+= 2u; else line
+= 1u;
7375 while (line
[wlen
] && line
[wlen
] != qch
) wlen
+= 1u;
7376 if (line
[wlen
] != qch
) ufoFatal("unterminated string literal");
7377 ufoCompileStrLitEx(line
, wlen
);
7378 line
+= wlen
+ 1u; // skip final quote
7379 } else if (wlen
== 1 && line
[0] == ':') {
7381 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7382 ufoMinInterpState
= UFO_MII_WORD_NAME
;
7384 } else if (wlen
== 1 && line
[0] == ';') {
7386 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected semicolon");
7387 ufoImgEmitU32(ufoFindWordChecked("FORTH:(EXIT)"));
7388 ufoMinInterpState
= UFO_MII_NO_WORD
;
7390 } else if (wlen
== 2 && line
[0] == '!' && line
[1] == ':') {
7391 // new immediate word
7392 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7393 ufoMinInterpState
= UFO_MII_WORD_NAME_IMM
;
7395 } else if (wlen
== 2 && line
[0] == '*' && line
[1] == ':') {
7397 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
7398 ufoMinInterpState
= UFO_MII_WORD_NAME_HIDDEN
;
7400 } else if (wlen
== 3 && memcmp(line
, "[']", 3) == 0) {
7402 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7403 ufoMinInterpState
= UFO_MII_WORD_CFA_LIT
;
7405 } else if (wlen
== 7 && ufoXStrEquCI("COMPILE", line
, wlen
)) {
7407 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7408 ufoMinInterpState
= UFO_MII_WORD_COMPILE
;
7410 } else if (wlen
== 9 && ufoXStrEquCI("[COMPILE]", line
, wlen
)) {
7412 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
7413 ufoMinInterpState
= UFO_MII_WORD_COMPILE_IMM
;
7417 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
7418 memcpy(wname
, line
, wlen
);
7420 cfa
= ufoFindWord(wname
);
7424 } else if (ufoTrySimpleNumber(line
, wlen
, &num
)) {
7425 // compile numeric literal
7428 // unknown word, this may be a forward reference, or a label definition
7429 // label defintion starts with "$"
7430 // (there are no words starting with "$" in the initial image)
7431 if (line
[0] == '$') {
7432 if (wlen
== 1) ufoFatal("dollar what?");
7433 if (wlen
> 2 && line
[wlen
- 1u] == ':') {
7435 lbl
= ufoFindAddLabel(line
, wlen
- 1u);
7436 if (lbl
->defined
) ufoFatal("double label '%s' definition", lbl
->name
);
7437 ufoFixLabelChainHere(lbl
);
7440 lbl
= ufoFindAddLabel(line
, wlen
);
7442 ufoImgEmitU32(lbl
->addr
);
7444 ufoEmitLabelChain(lbl
);
7448 // forward reference
7449 lbl
= ufoFindAddLabel(line
, wlen
);
7450 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
7451 ufoFatal("unknown word: '%s'", wname
);
7454 ufoEmitLabelChain(lbl
);
7464 //==========================================================================
7468 //==========================================================================
7469 UFO_DISABLE_INLINE
void ufoReset (void) {
7470 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
7472 ufoSP
= 0; ufoRP
= 0;
7473 ufoLP
= 0; ufoLBP
= 0;
7476 ufoVMStop
= 0; ufoVMAbort
= 0;
7481 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
7482 const uint32_t tibDef
= ufoImgGetU32(ufoAddrDefTIB
);
7483 ufoInitStateUserVars(ufoCurrState
, 0);
7485 ufoImgPutU32(ufoAddrTIBx
, tib
);
7486 ufoImgPutU32(ufoAddrDefTIB
, tibDef
);
7487 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
7490 ufoImgPutU32(ufoAddrDPTemp
, 0);
7492 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
7493 ufoVocSetOnlyDefs(ufoForthVocId
);
7497 //==========================================================================
7499 // ufoDefineEmitType
7501 //==========================================================================
7502 UFO_DISABLE_INLINE
void ufoDefineEmitType (void) {
7505 ufoInterpretLine(": EMIT ( ch -- ) (NORM-EMIT-CHAR) (EMIT) ;");
7509 ufoInterpretLine(": XEMIT ( ch -- ) (NORM-XEMIT-CHAR) (EMIT) ;");
7513 ufoInterpretLine(": CR ( -- ) NL (EMIT) ;");
7519 " LASTCR? FORTH:(TBRANCH) $endcr-exit CR "
7522 //ufoDecompileWord(ufoFindWordChecked("ENDCR"));
7526 ufoInterpretLine(": SPACE ( -- ) BL (EMIT) ;");
7531 ": SPACES ( count -- ) "
7533 " DUP 0> FORTH:(0BRANCH) $spaces-exit "
7535 " FORTH:(BRANCH) $spaces-again "
7541 // ( addr count -- )
7543 ": TYPE ( addr count -- ) "
7546 " DUP 0> FORTH:(0BRANCH) $type-exit "
7549 " FORTH:(BRANCH) $type-again "
7555 // ( addr count -- )
7557 ": XTYPE ( addr count -- ) "
7560 " DUP 0> FORTH:(0BRANCH) $xtype-exit "
7563 " FORTH:(BRANCH) $xtype-again "
7571 ": HERE ( -- here ) "
7572 " FORTH:(DP-TEMP) @ ?DUP "
7573 " FORTH:(TBRANCH) $here-exit "
7581 ": ALIGN-HERE ( -- ) "
7582 "$align-here-loop: "
7584 " FORTH:(0BRANCH) $align-here-exit "
7586 " FORTH:(BRANCH) $align-here-loop "
7587 "$align-here-exit: "
7591 // ( C:addr count -- ) ( E: -- addr count )
7593 ": STRLITERAL ( C:addr count -- ) ( E: -- addr count ) "
7594 " DUP 255 U> ` string literal too long` ?ERROR "
7595 " STATE @ FORTH:(0BRANCH) $strlit-exit "
7597 " ['] FORTH:(LITSTR8) COMPILE, "
7599 " ( compile length ) "
7601 " ( compile chars ) "
7603 " DUP 0<> FORTH:(0BRANCH) $strlit-loop-exit "
7605 " FORTH:(BRANCH) $strlit-loop "
7606 "$strlit-loop-exit: "
7608 " ( final 0: our counter is 0 here, so use it ) "
7614 // ( -- addr count )
7616 "!: \" ( -- addr count ) "
7617 " 34 PARSE ` string literal expected` ?NOT-ERROR "
7618 " COMPILER:(UNESCAPE) STRLITERAL "
7623 //==========================================================================
7625 // ufoDefineInterpret
7627 // define "INTERPRET" in Forth
7629 //==========================================================================
7630 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
7631 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
7633 // return "stop flag"
7635 "*: (UFO-INTERPRET-NEXT-LINE) ( -- continue? ) "
7636 " STATE @ FORTH:(TBRANCH) $ipn_incomp "
7637 " ( interpreter allowed to cross include boundary ) "
7638 " REFILL FORTH:(BRANCH) $ipn_done "
7640 " ( compiler is not allowed to cross include boundary ) "
7641 " REFILL-NOCROSS ` compiler cannot cross file boundaries` ?NOT-ERROR "
7646 ufoInterpNextLineCFA
= ufoFindWordChecked("FORTH:(UFO-INTERPRET-NEXT-LINE)");
7647 ufoInterpretLine("*: (INTERPRET-NEXT-LINE) (USER-INTERPRET-NEXT-LINE) @ EXECUTE-TAIL ;");
7649 // skip comments, parse name, refilling lines if necessary
7650 // returning FALSE as counter means: "no addr, exit INTERPRET"
7652 "*: (INTERPRET-PARSE-NAME) ( -- addr count / FALSE ) "
7653 "$label_ipn_again: "
7654 " TRUE (PARSE-SKIP-COMMENTS) PARSE-NAME "
7655 " DUP FORTH:(TBRANCH) $label_ipn_exit_fwd "
7656 " 2DROP (INTERPRET-NEXT-LINE) "
7657 " FORTH:(TBRANCH) $label_ipn_again "
7659 "$label_ipn_exit_fwd: "
7661 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
7666 " FORTH:(INTERPRET-PARSE-NAME) ( addr count / FALSE )"
7667 " ?DUP FORTH:(0BRANCH) $interp-done "
7668 " ( try defered checker ) "
7669 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7670 " FALSE (INTERPRET-CHECK-WORD) FORTH:(TBRANCH) $interp-again "
7671 " 2DUP FIND-WORD ( addr count cfa TRUE / addr count FALSE ) "
7672 " FORTH:(0BRANCH) $interp-try-number "
7674 " NROT 2DROP ( drop word string ) "
7675 " STATE @ FORTH:(0BRANCH) $interp-exec "
7676 " ( compiling; check immediate bit ) "
7677 " DUP CFA->NFA @ COMPILER:(WFLAG-IMMEDIATE) AND FORTH:(TBRANCH) $interp-exec "
7679 " FORTH:COMPILE, FORTH:(BRANCH) $interp-again "
7682 " EXECUTE FORTH:(BRANCH) $interp-again "
7683 " ( not a word, try a number ) "
7684 "$interp-try-number: "
7685 " 2DUP TRUE BASE @ (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE ) "
7686 " FORTH:(0BRANCH) $interp-number-error "
7688 " NROT 2DROP ( drop word string ) "
7689 " ( do we need to compile it? ) "
7690 " STATE @ FORTH:(0BRANCH) $interp-again "
7691 " COMPILE FORTH:(LIT) FORTH:, "
7692 " FORTH:(BRANCH) $interp-again "
7694 "$interp-number-error: "
7695 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7696 " FALSE (INTERPRET-WORD-NOT-FOUND) FORTH:(TBRANCH) $interp-again "
7697 " ENDCR SPACE XTYPE ` -- wut?` TYPE CR "
7698 " ` unknown word` ERROR "
7701 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
7705 //==========================================================================
7709 //==========================================================================
7710 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
7711 uint32_t imgAddr
= 0;
7713 // reserve 32 bytes for nothing
7714 for (uint32_t f
= 0; f
< 32; f
+= 1) {
7715 ufoImgPutU8(imgAddr
, 0);
7719 while ((imgAddr
& 3) != 0) {
7720 ufoImgPutU8(imgAddr
, 0);
7725 ufoAddrDP
= imgAddr
;
7726 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7729 ufoAddrDPTemp
= imgAddr
;
7730 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7733 ufoAddrLastXFA
= imgAddr
;
7734 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7737 ufoAddrVocLink
= imgAddr
;
7738 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
7741 ufoAddrNewWordFlags
= imgAddr
;
7742 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
7744 // WORD-REDEFINE-WARN-MODE
7745 ufoAddrRedefineWarning
= imgAddr
;
7746 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
7748 // setup (DP) and (DP-TEMP)
7749 ufoImgPutU32(ufoAddrDP
, imgAddr
);
7750 ufoImgPutU32(ufoAddrDPTemp
, 0);
7753 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
7758 //==========================================================================
7760 // ufoInitStateUserVars
7762 //==========================================================================
7763 static void ufoInitStateUserVars (UfoState
*st
, uint32_t cfa
) {
7764 ufo_assert(st
!= NULL
);
7765 if (st
->imageTempSize
< 8192u) {
7766 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
7767 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
7768 st
->imageTemp
= itmp
;
7769 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
7770 st
->imageTempSize
= 8192;
7772 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
7773 st
->imageTemp
[(ufoAddrSTATE
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7774 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
7775 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7776 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
7777 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7778 st
->imageTemp
[(ufoAddrContext
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7779 st
->imageTemp
[(ufoAddrCurrent
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
7780 st
->imageTemp
[(ufoAddrSelf
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7781 st
->imageTemp
[(ufoAddrInterNextLine
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoInterpNextLineCFA
;
7782 st
->imageTemp
[(ufoAddrEP
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
7783 // init other things, because this procedure is used in `ufoReset()` too
7784 st
->SP
= 0; st
->RP
= 0; st
->RPTop
= 0; st
->regA
= 0;
7785 st
->LP
= 0; st
->LBP
= 0; st
->vmRPopCFA
= 0;
7790 st
->rStack
[0] = 0xdeadf00d; // dummy value
7791 st
->rStack
[1] = cfa
;
7797 //==========================================================================
7799 // ufoInitBasicWords
7801 //==========================================================================
7802 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
7803 ufoDefineConstant("FALSE", 0);
7804 ufoDefineConstant("TRUE", ufoTrueValue
);
7806 ufoDefineConstant("BL", 32);
7807 ufoDefineConstant("NL", 10);
7810 ufoDefineUserVar("BASE", ufoAddrBASE
);
7811 ufoDefineUserVar("TIB", ufoAddrTIBx
);
7812 ufoDefineUserVar(">IN", ufoAddrINx
);
7813 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
7814 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
7815 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
7816 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
7817 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
7818 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
7820 ufoDefineUserVar("STATE", ufoAddrSTATE
);
7821 ufoDefineConstant("CONTEXT", ufoAddrContext
);
7822 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
7823 ufoDefineConstant("(SELF)", ufoAddrSelf
); // used in OOP implementations
7824 ufoDefineConstant("(USER-INTERPRET-NEXT-LINE)", ufoAddrInterNextLine
);
7825 ufoDefineConstant("(EXC-FRAME-PTR)", ufoAddrEP
);
7828 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
7829 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
7830 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
7831 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
7832 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
7833 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
7834 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
7836 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
7837 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
7838 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
7840 ufoDefineConstant("(DP)", ufoAddrDP
);
7841 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
7844 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
7845 UFWORDX("SP0!", SP0_STORE
);
7846 UFWORDX("RP0!", RP0_STORE
);
7848 UFWORDX("PAD", PAD
);
7851 UFWORDX("C@", CPEEK
);
7852 UFWORDX("W@", WPEEK
);
7855 UFWORDX("C!", CPOKE
);
7856 UFWORDX("W!", WPOKE
);
7858 UFWORDX(",", COMMA
);
7859 UFWORDX("C,", CCOMMA
);
7860 UFWORDX("W,", WCOMMA
);
7862 UFWORDX("A>", REGA_LOAD
);
7863 UFWORDX(">A", REGA_STORE
);
7864 UFWORDX("A-SWAP", REGA_SWAP
);
7865 UFWORDX("+1>A", REGA_INC
);
7866 UFWORDX("+4>A", REGA_INC_CELL
);
7867 UFWORDX("A>R", REGA_TO_R
);
7868 UFWORDX("R>A", R_TO_REGA
);
7870 UFWORDX("@A+", PEEK_REGA_IDX
);
7871 UFWORDX("C@A+", CPEEK_REGA_IDX
);
7872 UFWORDX("W@A+", WPEEK_REGA_IDX
);
7874 UFWORDX("!A+", POKE_REGA_IDX
);
7875 UFWORDX("C!A+", CPOKE_REGA_IDX
);
7876 UFWORDX("W!A+", WPOKE_REGA_IDX
);
7879 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
7880 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
7881 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
7882 UFWORDX("(LITSTR8)", PAR_LITSTR8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
7883 UFWORDX("(EXIT)", PAR_EXIT
);
7885 ufoLitStr8CFA
= ufoFindWordChecked("FORTH:(LITSTR8)");
7887 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
7888 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
7889 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
7890 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
7892 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7893 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7894 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7895 UFWORDX("(+0BRANCH)", PAR_P0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7896 UFWORDX("(+BRANCH)", PAR_PBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7897 UFWORDX("(-0BRANCH)", PAR_M0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7898 UFWORDX("(-BRANCH)", PAR_MBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7899 UFWORDX("(DATASKIP)", PAR_DATASKIP
); ufoSetLatestArgs(UFW_WARG_DATASKIP
);
7900 UFWORDX("(OR-BRANCH)", PAR_OR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7901 UFWORDX("(AND-BRANCH)", PAR_AND_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7902 UFWORDX("(CASE-BRANCH)", PAR_CASE_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
7907 //==========================================================================
7909 // ufoInitBasicCompilerWords
7911 //==========================================================================
7912 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
7913 // create "COMPILER" vocabulary
7914 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
7915 ufoVocSetOnlyDefs(ufoCompilerVocId
);
7917 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
7918 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
7919 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
7920 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
7921 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
7922 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
7923 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
7924 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
7926 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
7927 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
7928 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
7929 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
7930 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
7931 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
7932 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
7933 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
7935 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
7936 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
7937 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
7938 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
7939 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
7940 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
7941 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
7942 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
7943 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
7945 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
7946 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
7947 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
7948 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
7949 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
7950 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
7951 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
7953 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
7954 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
7955 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
7956 ufoDefineConstant("(REDEFINE-WARN-PARENTS)", UFO_REDEF_WARN_PARENTS
);
7958 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
7960 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
7964 " FORTH:STATE FORTH:@ ` expecting interpretation mode` FORTH:?ERROR "
7969 " FORTH:STATE FORTH:@ ` expecting compilation mode` FORTH:?NOT-ERROR "
7972 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
7973 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
7975 ufoVocSetOnlyDefs(ufoForthVocId
);
7978 ufoInterpretLine("!: [ COMPILER:?COMP 0 STATE ! ;");
7980 ufoInterpretLine(": ] COMPILER:?EXEC 1 STATE ! ;");
7984 //==========================================================================
7988 //==========================================================================
7989 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
7990 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
7992 UFWORDX("CFA->PFA", CFA2PFA
);
7993 UFWORDX("CFA->NFA", CFA2NFA
);
7994 UFWORDX("CFA->LFA", CFA2LFA
);
7995 UFWORDX("CFA->WEND", CFA2WEND
);
7997 UFWORDX("PFA->CFA", PFA2CFA
);
7998 UFWORDX("PFA->NFA", PFA2NFA
);
8000 UFWORDX("NFA->CFA", NFA2CFA
);
8001 UFWORDX("NFA->PFA", NFA2PFA
);
8002 UFWORDX("NFA->LFA", NFA2LFA
);
8004 UFWORDX("LFA->CFA", LFA2CFA
);
8005 UFWORDX("LFA->PFA", LFA2PFA
);
8006 UFWORDX("LFA->BFA", LFA2BFA
);
8007 UFWORDX("LFA->XFA", LFA2XFA
);
8008 UFWORDX("LFA->YFA", LFA2YFA
);
8009 UFWORDX("LFA->NFA", LFA2NFA
);
8011 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
8012 UFWORDX("FIND-WORD", FIND_WORD
);
8013 UFWORDX("(FIND-WORD-IN-VOC)", FIND_WORD_IN_VOC
);
8014 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", FIND_WORD_IN_VOC_AND_PARENTS
);
8017 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
8018 UFWORDX("(FORTH-CALL)", FORTH_CALL
);
8021 UFWORDX("?DUP", QDUP
);
8022 UFWORDX("2DUP", DDUP
);
8024 UFWORDX("2DROP", DDROP
);
8026 UFWORDX("2SWAP", DSWAP
);
8028 UFWORDX("2OVER", DOVER
);
8031 UFWORDX("PICK", PICK
);
8032 UFWORDX("ROLL", ROLL
);
8036 UFWORDX(">R", DTOR
);
8037 UFWORDX("R>", RTOD
);
8038 UFWORDX("R@", RPEEK
);
8039 UFWORDX("RPICK", RPICK
);
8040 UFWORDX("RROLL", RROLL
);
8041 UFWORDX("RSWAP", RSWAP
);
8042 UFWORDX("ROVER", ROVER
);
8043 UFWORDX("RROT", RROT
);
8044 UFWORDX("RNROT", RNROT
);
8046 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
8047 UFWORDX("(EMIT)", PAR_EMIT
);
8048 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR
);
8049 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR
);
8050 UFWORDX("LASTCR?", LASTCRQ
);
8051 UFWORDX("LASTCR!", LASTCRSET
);
8055 UFWORDX("-", MINUS
);
8057 UFWORDX("U*", UMUL
);
8059 UFWORDX("U/", UDIV
);
8060 UFWORDX("MOD", MOD
);
8061 UFWORDX("UMOD", UMOD
);
8062 UFWORDX("/MOD", DIVMOD
);
8063 UFWORDX("U/MOD", UDIVMOD
);
8064 UFWORDX("*/", MULDIV
);
8065 UFWORDX("U*/", UMULDIV
);
8066 UFWORDX("*/MOD", MULDIVMOD
);
8067 UFWORDX("U*/MOD", UMULDIVMOD
);
8068 UFWORDX("M*", MMUL
);
8069 UFWORDX("UM*", UMMUL
);
8070 UFWORDX("M/MOD", MDIVMOD
);
8071 UFWORDX("UM/MOD", UMDIVMOD
);
8072 UFWORDX("UDS*", UDSMUL
);
8074 UFWORDX("SM/REM", SMREM
);
8075 UFWORDX("FM/MOD", FMMOD
);
8077 UFWORDX("D-", DMINUS
);
8078 UFWORDX("D+", DPLUS
);
8079 UFWORDX("D=", DEQU
);
8080 UFWORDX("D<", DLESS
);
8081 UFWORDX("D<=", DLESSEQU
);
8082 UFWORDX("DU<", DULESS
);
8083 UFWORDX("DU<=", DULESSEQU
);
8090 UFWORDX(">", GREAT
);
8091 UFWORDX("<=", LESSEQU
);
8092 UFWORDX(">=", GREATEQU
);
8093 UFWORDX("U<", ULESS
);
8094 UFWORDX("U>", UGREAT
);
8095 UFWORDX("U<=", ULESSEQU
);
8096 UFWORDX("U>=", UGREATEQU
);
8098 UFWORDX("<>", NOTEQU
);
8100 UFWORDX("0=", ZERO_EQU
);
8101 UFWORDX("0<>", ZERO_NOTEQU
);
8103 UFWORDX("NOT", ZERO_EQU
);
8104 UFWORDX("NOTNOT", ZERO_NOTEQU
);
8110 UFWORDX("LOGAND", LOGAND
);
8111 UFWORDX("LOGOR", LOGOR
);
8114 UFWORDX("(TIB-IN)", TIB_IN
);
8115 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
8116 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
8117 UFWORDX("TIB-GETCH", TIB_GETCH
);
8118 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
8120 UFWORDX("REFILL", REFILL
);
8121 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
8124 UFWORDX("(PARSE)", PAR_PARSE
);
8125 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
8127 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
8128 UFWORDX("PARSE-NAME", PARSE_NAME
);
8129 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
8130 UFWORDX("PARSE", PARSE
);
8133 UFWORDX("(VSP@)", PAR_GET_VSP
);
8134 UFWORDX("(VSP!)", PAR_SET_VSP
);
8135 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
8136 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
8137 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
8139 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
8140 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
8141 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
8144 UFWORDX("ERROR", ERROR
);
8145 UFWORDX("FATAL-ERROR", ERROR
);
8147 ufoInterpretLine(": 1+ ( n -- n+1 ) 1 + ;");
8148 ufoInterpretLine(": 1- ( n -- n-1 ) 1 - ;");
8149 ufoInterpretLine(": 2+ ( n -- n+2 ) 2 + ;");
8150 ufoInterpretLine(": 2- ( n -- n-2 ) 2 - ;");
8151 ufoInterpretLine(": 4+ ( n -- n+4 ) 4 + ;");
8152 ufoInterpretLine(": 4- ( n -- n-4 ) 4 - ;");
8154 ufoInterpretLine(": 2* ( n -- n*2 ) 1 ASH ;");
8155 ufoInterpretLine(": 2/ ( n -- n/2 ) -1 ASH ;");
8156 ufoInterpretLine(": 4* ( n -- n*4 ) 2 ASH ;");
8157 ufoInterpretLine(": 4/ ( n -- n/4 ) -2 ASH ;");
8159 ufoInterpretLine(": 2U* ( u -- u*2 ) 1 LSH ;");
8160 ufoInterpretLine(": 2U/ ( u -- u/2 ) -1 LSH ;");
8161 ufoInterpretLine(": 4U* ( u -- u*4 ) 2 LSH ;");
8162 ufoInterpretLine(": 4U/ ( u -- u/4 ) -2 LSH ;");
8164 ufoInterpretLine(": 0< ( n -- n<0 ) 0 < ;");
8165 ufoInterpretLine(": 0> ( n -- n>0 ) 0 > ;");
8166 ufoInterpretLine(": 0<= ( n -- n<0 ) 0 <= ;");
8167 ufoInterpretLine(": 0>= ( n -- n>0 ) 0 >= ;");
8169 ufoInterpretLine(": @A ( idx -- v ) 0 @A+ ;");
8170 ufoInterpretLine(": C@A ( idx -- v ) 0 C@A+ ;");
8171 ufoInterpretLine(": W@A ( idx -- v ) 0 W@A+ ;");
8173 ufoInterpretLine(": !A ( idx -- v ) 0 !A+ ;");
8174 ufoInterpretLine(": C!A ( idx -- v ) 0 C!A+ ;");
8175 ufoInterpretLine(": W!A ( idx -- v ) 0 W!A+ ;");
8179 ufoInterpretLine(": ABORT ` \"ABORT\" called` ERROR ;");
8182 // ( errflag addr count -- )
8184 ": ?ERROR ( errflag addr count -- ) "
8185 " ROT FORTH:(0BRANCH) $qerr_skip ERROR "
8191 // ( errflag addr count -- )
8193 ": ?NOT-ERROR ( errflag addr count -- ) "
8194 " ROT FORTH:(TBRANCH) $qnoterr_skip ERROR "
8200 ": FIND-WORD-IN-VOC ( vocid addr count -- cfa TRUE / FALSE ) "
8201 " 0 (FIND-WORD-IN-VOC) ;");
8204 ": FIND-WORD-IN-VOC-AND-PARENTS ( vocid addr count -- cfa TRUE / FALSE ) "
8205 " 0 (FIND-WORD-IN-VOC-AND-PARENTS) ;");
8207 UFWORDX("GET-MSECS", GET_MSECS
);
8211 //==========================================================================
8213 // ufoInitHandleWords
8215 //==========================================================================
8216 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
8217 // create "HANDLE" vocabulary
8218 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
8219 ufoVocSetOnlyDefs(handleVocId
);
8220 UFWORDX("NEW", PAR_NEW_HANDLE
);
8221 UFWORDX("FREE", PAR_FREE_HANDLE
);
8222 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
8223 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
8224 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
8225 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
8226 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
8227 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
8228 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
8229 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
8230 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
8231 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
8232 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
8233 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
8234 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
8235 ufoVocSetOnlyDefs(ufoForthVocId
);
8239 //==========================================================================
8241 // ufoInitHigherWords
8243 //==========================================================================
8244 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
8245 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
8246 UFWORDX("(INCLUDE-DROP)", PAR_INCLUDE_DROP
);
8247 UFWORDX("(INCLUDE-BUILD-NAME)", PAR_INCLUDE_BUILD_NAME
);
8248 UFWORDX("(INCLUDE-NO-REFILL)", PAR_INCLUDE_NO_REFILL
);
8249 UFWORDX("(INCLUDE-LINE-SEEK)", PAR_INCLUDE_LINE_SEEK
);
8251 UFWORDX("(INCLUDE-LINE-FOFS)", PAR_INCLUDE_LINE_FOFS
);
8252 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
8253 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
8254 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
8255 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
8257 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
8258 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
8259 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
8261 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
8262 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
8266 //==========================================================================
8268 // ufoInitStringWords
8270 //==========================================================================
8271 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
8272 // create "STRING" vocabulary
8273 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
8274 ufoVocSetOnlyDefs(stringVocId
);
8275 UFWORDX("=", STREQU
);
8276 UFWORDX("=CI", STREQUCI
);
8277 UFWORDX("SEARCH", SEARCH
);
8278 UFWORDX("HASH", STRHASH
);
8279 UFWORDX("HASH-CI", STRHASHCI
);
8280 ufoVocSetOnlyDefs(ufoForthVocId
);
8284 //==========================================================================
8286 // ufoInitDebugWords
8288 //==========================================================================
8289 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
8290 // create "DEBUG" vocabulary
8291 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
8292 ufoVocSetOnlyDefs(debugVocId
);
8293 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
8294 UFWORDX("(DECOMPILE-MEM)", DEBUG_DECOMPILE_MEM
);
8295 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
8296 UFWORDX("DUMP-STACK", DUMP_STACK
);
8297 UFWORDX("BACKTRACE-TASK", UFO_BACKTRACE_TASK
);
8298 UFWORDX("DUMP-STACK-TASK", DUMP_STACK_TASK
);
8299 UFWORDX("DUMP-RSTACK-TASK", DUMP_RSTACK_TASK
);
8300 UFWORDX("(BP)", MT_DEBUGGER_BP
);
8301 UFWORDX("IP->NFA", IP2NFA
);
8302 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
8303 UFWORDX("IP->FILE-HASH/LINE", IP2FILEHASHLINE
);
8304 ufoVocSetOnlyDefs(ufoForthVocId
);
8308 //==========================================================================
8312 //==========================================================================
8313 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
8314 // create "MTASK" vocabulary
8315 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
8316 ufoVocSetOnlyDefs(mtVocId
);
8317 UFWORDX("NEW-STATE", MT_NEW_STATE
);
8318 UFWORDX("FREE-STATE", MT_FREE_STATE
);
8319 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
8320 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
8321 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
8322 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
8323 UFWORDX("YIELD-TO", MT_YIELD_TO
);
8324 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
8325 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
8326 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
8327 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
8328 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
8329 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
8330 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
8331 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
8332 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
8333 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
8334 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
8335 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
8336 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
8337 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
8338 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
8339 UFWORDX("STATE-LP@", MT_LP_GET
);
8340 UFWORDX("STATE-LBP@", MT_LBP_GET
);
8341 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
8342 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
8343 UFWORDX("STATE-LP!", MT_LP_SET
);
8344 UFWORDX("STATE-LBP!", MT_LBP_SET
);
8345 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
8346 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
8347 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
8348 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
8349 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
8350 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
8351 UFWORDX("STATE-VSP@", MT_VSP_GET
);
8352 UFWORDX("STATE-VSP!", MT_VSP_SET
);
8353 UFWORDX("STATE-VSP-AT@", MT_VSP_LOAD
);
8354 UFWORDX("STATE-VSP-AT!", MT_VSP_STORE
);
8355 ufoVocSetOnlyDefs(ufoForthVocId
);
8359 //==========================================================================
8363 //==========================================================================
8364 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
8365 // create "TTY" vocabulary
8366 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
8367 ufoVocSetOnlyDefs(ttyVocId
);
8368 UFWORDX("TTY?", TTY_TTYQ
);
8369 UFWORDX("RAW?", TTY_RAWQ
);
8370 UFWORDX("SIZE", TTY_SIZE
);
8371 UFWORDX("SET-RAW", TTY_SET_RAW
);
8372 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
8373 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
8374 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
8375 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
8376 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
8377 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
8378 ufoVocSetOnlyDefs(ufoForthVocId
);
8382 //==========================================================================
8384 // ufoInitFilesWords
8386 //==========================================================================
8387 UFO_DISABLE_INLINE
void ufoInitFilesWords (void) {
8388 // create "FILES" vocabulary
8389 const uint32_t filesVocId
= ufoCreateVoc("FILES", 0, UFW_FLAG_PROTECTED
);
8390 ufoVocSetOnlyDefs(filesVocId
);
8391 ufoDefineConstant("SEEK-SET", SEEK_SET
);
8392 ufoDefineConstant("SEEK-CUR", SEEK_CUR
);
8393 ufoDefineConstant("SEEK-END", SEEK_END
);
8395 UFWORDX("OPEN-R/O", FILES_OPEN_RO
);
8396 UFWORDX("OPEN-R/W", FILES_OPEN_RW
);
8397 UFWORDX("CREATE", FILES_CREATE
);
8398 UFWORDX("CLOSE", FILES_CLOSE
);
8399 UFWORDX("TELL", FILES_TELL
);
8400 UFWORDX("SEEK-EX", FILES_SEEK_EX
);
8401 UFWORDX("SIZE", FILES_SIZE
);
8402 UFWORDX("READ", FILES_READ
);
8403 UFWORDX("READ-EXACT", FILES_READ_EXACT
);
8404 UFWORDX("WRITE", FILES_WRITE
);
8406 UFWORDX("UNLINK", FILES_UNLINK
);
8408 UFWORDX("ERRNO", FILES_ERRNO
);
8411 ": SEEK ( ofs handle -- success? ) "
8412 " SEEK-SET FORTH:SWAP SEEK-EX "
8417 ": READ-EXACT ( addr count handle -- success? ) "
8418 " FORTH:OVER FORTH:>R ( save count ) "
8419 " READ FORTH:DUP FORTH:(0BRANCH) $files-read-exact-error "
8420 " FORTH:DROP ( drop TRUE ) FORTH:R@ = "
8421 "$files-read-exact-error: "
8426 ufoVocSetOnlyDefs(ufoForthVocId
);
8430 //==========================================================================
8432 // ufoInitVeryVeryHighWords
8434 //==========================================================================
8435 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
8437 //ufoDefineDefer("INTERPRET", idumbCFA);
8439 ufoDefineEmitType();
8441 // ( addr count FALSE -- addr count FALSE / TRUE )
8442 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
8444 // ( addr count FALSE -- addr count FALSE / TRUE )
8445 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
8447 // ( -- ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
8448 ufoDefineSColonForth("(EXIT-EXTENDER)");
8452 ufoInterpretLine("!: EXIT ( -- ) COMPILER:?COMP (EXIT-EXTENDER) COMPILE FORTH:(EXIT) ;");
8454 ufoDefineInterpret();
8456 //ufoDumpVocab(ufoCompilerVocId);
8459 ": RUN-INTERPRET-LOOP "
8460 "$run-interp-loop-again: "
8461 " RP0! INTERPRET (UFO-INTERPRET-FINISHED-ACTION) "
8462 " FORTH:(BRANCH) $run-interp-loop-again "
8466 #define UFO_ADD_DO_CFA(cfx_) do { \
8467 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
8468 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
8473 //==========================================================================
8477 //==========================================================================
8478 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
8480 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
8482 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
8484 // allocate default TIB handle
8485 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
8486 //ufoDefTIB = tibh->ufoHandle;
8488 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
8489 UFO_ADD_DO_CFA(Forth
);
8490 UFO_ADD_DO_CFA(Variable
);
8491 UFO_ADD_DO_CFA(Value
);
8492 UFO_ADD_DO_CFA(Const
);
8493 UFO_ADD_DO_CFA(Defer
);
8494 UFO_ADD_DO_CFA(Voc
);
8495 UFO_ADD_DO_CFA(Create
);
8496 UFO_ADD_DO_CFA(UserVariable
);
8498 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
8502 // create "FORTH" vocabulary (it should be the first one)
8503 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
8504 ufoVocSetOnlyDefs(ufoForthVocId
);
8506 // base low-level interpreter words
8507 ufoInitBasicWords();
8512 // some COMPILER words
8513 ufoInitBasicCompilerWords();
8515 // STRING vocabulary
8516 ufoInitStringWords();
8519 ufoInitDebugWords();
8524 // HANDLE vocabulary
8525 ufoInitHandleWords();
8531 ufoInitFilesWords();
8533 // some higher-level FORTH words (includes, etc.)
8534 ufoInitHigherWords();
8536 // very-very high-level FORTH words
8537 ufoInitVeryVeryHighWords();
8539 ufoFinalLabelCheck();
8542 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
8551 // ////////////////////////////////////////////////////////////////////////// //
8552 // virtual machine executor
8556 //==========================================================================
8560 // address interpreter
8562 //==========================================================================
8563 static void ufoRunVMCFA (uint32_t cfa
) {
8564 const uint32_t oldRPTop
= ufoRPTop
;
8566 #ifdef UFO_TRACE_VM_RUN
8567 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
8573 // VM execution loop
8575 if (ufoVMAbort
) ufoFatal("user abort");
8576 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
8577 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
8578 if (ufoVMRPopCFA
== 0) {
8580 if (ufoIP
== 0) ufoFatal("IP is NULL");
8581 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
8582 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
8584 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
8587 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
8588 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
8589 // get next word CFAIDX, and check it
8590 uint32_t cfaidx
= ufoImgGetU32(cfa
);
8591 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
8592 #ifdef UFO_TRACE_VM_RUN
8593 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
8595 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
8596 fprintf(stderr
, "######################################\n");
8598 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
8599 cfaidx
&= UFO_ADDR_CFA_MASK
;
8600 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
8601 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
8602 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
8604 #ifdef UFO_TRACE_VM_RUN
8605 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
8606 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
8608 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
8610 // if CFA points somewhere inside a dict, this is "DOES>" word
8611 // IP points to PFA we need to push
8612 // CFA points to Forth word we need to jump to
8613 #ifdef UFO_TRACE_VM_DOER
8614 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
8615 UFCALL(UFO_BACKTRACE
);
8617 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
8618 ufoRPush(ufoIP
); // push IP
8619 ufoIP
= cfaidx
; // fix IP
8621 // that's all we need to activate the debugger
8622 if (ufoSingleStep
) {
8624 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
8625 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
8626 UfoState
*ost
= ufoCurrState
;
8627 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
8632 } while (ufoRP
!= oldRPTop
);
8637 // ////////////////////////////////////////////////////////////////////////// //
8641 //==========================================================================
8645 // register new word
8647 //==========================================================================
8648 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
8649 ufo_assert(cfa
!= NULL
);
8650 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8651 uint32_t cfaidx
= ufoCFAsUsed
;
8652 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
8653 ufoForthCFAs
[cfaidx
] = cfa
;
8655 //ufoDefineNative(wname, xcfa, 0);
8656 cfaidx
|= UFO_ADDR_CFA_BIT
;
8657 flags
&= 0xffffff00u
;
8658 ufoCreateWordHeader(wname
, flags
);
8659 const uint32_t res
= UFO_GET_DP();
8660 ufoImgEmitU32(cfaidx
);
8665 //==========================================================================
8667 // ufoRegisterDataWord
8669 //==========================================================================
8670 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
8673 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
8674 flags
&= 0xffffff00u
;
8675 ufoCreateWordHeader(wname
, flags
);
8676 ufoImgEmitU32(cfaidx
);
8677 const uint32_t res
= UFO_GET_DP();
8678 ufoImgEmitU32(value
);
8683 //==========================================================================
8685 // ufoRegisterConstant
8687 //==========================================================================
8688 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
8689 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
8693 //==========================================================================
8695 // ufoRegisterVariable
8697 //==========================================================================
8698 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
8699 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
8703 //==========================================================================
8707 //==========================================================================
8708 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
8709 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
8713 //==========================================================================
8717 //==========================================================================
8718 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
8719 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
8723 //==========================================================================
8725 // ufoFindWordInVocabulary
8727 // check if we have the corresponding word.
8728 // return CFA suitable for executing, or 0.
8730 //==========================================================================
8731 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
8732 if (wname
== NULL
|| wname
[0] == 0) return 0;
8733 size_t wlen
= strlen(wname
);
8734 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
8735 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
8739 //==========================================================================
8743 //==========================================================================
8744 uint32_t ufoGetIP (void) {
8749 //==========================================================================
8753 //==========================================================================
8754 void ufoSetIP (uint32_t newip
) {
8759 //==========================================================================
8763 //==========================================================================
8764 int ufoIsExecuting (void) {
8765 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
8769 //==========================================================================
8773 //==========================================================================
8774 int ufoIsCompiling (void) {
8775 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
8779 //==========================================================================
8783 //==========================================================================
8784 void ufoSetExecuting (void) {
8785 ufoImgPutU32(ufoAddrSTATE
, 0);
8789 //==========================================================================
8793 //==========================================================================
8794 void ufoSetCompiling (void) {
8795 ufoImgPutU32(ufoAddrSTATE
, 1);
8799 //==========================================================================
8803 //==========================================================================
8804 uint32_t ufoGetHere () {
8805 return UFO_GET_DP();
8809 //==========================================================================
8813 //==========================================================================
8814 uint32_t ufoGetPad () {
8820 //==========================================================================
8824 //==========================================================================
8825 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
8826 return ufoTibPeekChOfs(ofs
);
8830 //==========================================================================
8834 //==========================================================================
8835 uint8_t ufoTIBGetCh (void) {
8836 return ufoTibGetCh();
8840 //==========================================================================
8844 //==========================================================================
8845 void ufoTIBSkipCh (void) {
8850 //==========================================================================
8856 //==========================================================================
8857 int ufoTIBSRefill (int allowCrossIncludes
) {
8858 return ufoLoadNextLine(allowCrossIncludes
);
8862 //==========================================================================
8866 //==========================================================================
8867 uint32_t ufoPeekData (void) {
8872 //==========================================================================
8876 //==========================================================================
8877 uint32_t ufoPopData (void) {
8882 //==========================================================================
8886 //==========================================================================
8887 void ufoPushData (uint32_t value
) {
8888 return ufoPush(value
);
8892 //==========================================================================
8896 //==========================================================================
8897 void ufoPushBoolData (int val
) {
8902 //==========================================================================
8906 //==========================================================================
8907 uint32_t ufoPeekRet (void) {
8912 //==========================================================================
8916 //==========================================================================
8917 uint32_t ufoPopRet (void) {
8922 //==========================================================================
8926 //==========================================================================
8927 void ufoPushRet (uint32_t value
) {
8928 return ufoRPush(value
);
8932 //==========================================================================
8936 //==========================================================================
8937 void ufoPushBoolRet (int val
) {
8938 ufoRPush(val
? ufoTrueValue
: 0);
8942 //==========================================================================
8946 //==========================================================================
8947 uint8_t ufoPeekByte (uint32_t addr
) {
8948 return ufoImgGetU8Ext(addr
);
8952 //==========================================================================
8956 //==========================================================================
8957 uint16_t ufoPeekWord (uint32_t addr
) {
8964 //==========================================================================
8968 //==========================================================================
8969 uint32_t ufoPeekCell (uint32_t addr
) {
8976 //==========================================================================
8980 //==========================================================================
8981 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
8982 ufoImgPutU8(addr
, value
);
8986 //==========================================================================
8990 //==========================================================================
8991 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
8998 //==========================================================================
9002 //==========================================================================
9003 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
9010 //==========================================================================
9014 //==========================================================================
9015 uint32_t ufoGetPAD (void) {
9016 return UFO_PAD_ADDR
;
9020 //==========================================================================
9024 //==========================================================================
9025 void ufoEmitByte (uint32_t value
) {
9026 ufoImgEmitU8(value
);
9030 //==========================================================================
9034 //==========================================================================
9035 void ufoEmitWord (uint32_t value
) {
9036 ufoImgEmitU8(value
& 0xff);
9037 ufoImgEmitU8((value
>> 8) & 0xff);
9041 //==========================================================================
9045 //==========================================================================
9046 void ufoEmitCell (uint32_t value
) {
9047 ufoImgEmitU32(value
);
9051 //==========================================================================
9055 //==========================================================================
9056 int ufoIsInited (void) {
9057 return (ufoMode
!= UFO_MODE_NONE
);
9061 static void (*ufoUserPostInitCB
) (void);
9064 //==========================================================================
9066 // ufoSetUserPostInit
9068 // called after main initialisation
9070 //==========================================================================
9071 void ufoSetUserPostInit (void (*cb
) (void)) {
9072 ufoUserPostInitCB
= cb
;
9076 //==========================================================================
9080 //==========================================================================
9081 void ufoInit (void) {
9082 if (ufoMode
!= UFO_MODE_NONE
) return;
9083 ufoMode
= UFO_MODE_NATIVE
;
9086 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
9088 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
9090 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
9091 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
9093 ufoCurrState
= ufoNewState();
9094 strcpy(ufoCurrState
->name
, "MAIN");
9095 ufoInitStateUserVars(ufoCurrState
, 0);
9096 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
9097 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
9099 ufoYieldedState
= NULL
;
9100 ufoDebuggerState
= NULL
;
9103 #ifdef UFO_DEBUG_STARTUP_TIMES
9104 uint32_t stt
= ufo_get_msecs();
9105 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
9108 #ifdef UFO_DEBUG_STARTUP_TIMES
9109 uint32_t ett
= ufo_get_msecs();
9110 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
9115 if (ufoUserPostInitCB
) {
9116 ufoUserPostInitCB();
9121 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
9123 FILE *ufl
= fopen(ufmname
, "rb");
9125 FILE *ufl
= fopen(ufmname
, "r");
9129 ufoSetInFileNameReuse(ufmname
);
9131 ufoFileId
= ufoLastUsedFileId
;
9132 setLastIncPath(ufoInFileName
, 1);
9135 ufoFatal("cannot load init code");
9138 if (ufoInFile
!= NULL
) {
9139 ufoRunInterpretLoop();
9144 //==========================================================================
9148 //==========================================================================
9149 void ufoFinishVM (void) {
9154 //==========================================================================
9158 // check if VM was exited due to `ufoFinishVM()`
9160 //==========================================================================
9161 int ufoWasVMFinished (void) {
9162 return (ufoVMStop
!= 0);
9166 //==========================================================================
9170 // ( -- addr count TRUE / FALSE )
9171 // does base TIB parsing; never copies anything.
9172 // as our reader is line-based, returns FALSE on EOL.
9173 // EOL is detected after skipping leading delimiters.
9174 // passing -1 as delimiter skips the whole line, and always returns FALSE.
9175 // trailing delimiter is always skipped.
9176 // result is on the data stack.
9178 //==========================================================================
9179 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
9180 ufoPush(delim
); ufoPushBool(skipLeading
);
9184 //==========================================================================
9188 // ( -- addr count )
9189 // parse with leading blanks skipping. doesn't copy anything.
9190 // return empty string on EOL.
9192 //==========================================================================
9193 void ufoCallParseName (void) {
9198 //==========================================================================
9202 // ( -- addr count TRUE / FALSE )
9203 // parse without skipping delimiters; never copies anything.
9204 // as our reader is line-based, returns FALSE on EOL.
9205 // passing 0 as delimiter skips the whole line, and always returns FALSE.
9206 // trailing delimiter is always skipped.
9208 //==========================================================================
9209 void ufoCallParse (uint32_t delim
) {
9215 //==========================================================================
9217 // ufoCallParseSkipBlanks
9219 //==========================================================================
9220 void ufoCallParseSkipBlanks (void) {
9221 UFCALL(PARSE_SKIP_BLANKS
);
9225 //==========================================================================
9227 // ufoCallParseSkipComments
9229 //==========================================================================
9230 void ufoCallParseSkipComments (void) {
9231 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9235 //==========================================================================
9237 // ufoCallParseSkipLineComments
9239 //==========================================================================
9240 void ufoCallParseSkipLineComments (void) {
9241 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
9245 //==========================================================================
9247 // ufoCallParseSkipLine
9249 // to the end of line; doesn't refill
9251 //==========================================================================
9252 void ufoCallParseSkipLine (void) {
9253 UFCALL(PARSE_SKIP_LINE
);
9257 //==========================================================================
9259 // ufoCallBasedNumber
9261 // convert number from addrl+1
9262 // returns address of the first inconvertible char
9263 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
9265 //==========================================================================
9266 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
9267 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
9268 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
9269 UFCALL(PAR_BASED_NUMBER
);
9273 //==========================================================================
9277 //==========================================================================
9278 void ufoRunWord (uint32_t cfa
) {
9280 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9281 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9282 ufoMode
= UFO_MODE_NATIVE
;
9290 //==========================================================================
9294 //==========================================================================
9295 void ufoRunMacroWord (uint32_t cfa
) {
9297 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
9298 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
9299 ufoMode
= UFO_MODE_MACRO
;
9300 const uint32_t oisp
= ufoFileStackPos
;
9303 (void)ufoLoadNextUserLine();
9308 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
9313 //==========================================================================
9317 // check if we are currently in "MACRO" mode.
9318 // should be called from registered words.
9320 //==========================================================================
9321 int ufoIsInMacroMode (void) {
9322 return (ufoMode
== UFO_MODE_MACRO
);
9326 //==========================================================================
9328 // ufoRunInterpretLoop
9330 // run default interpret loop.
9332 //==========================================================================
9333 void ufoRunInterpretLoop (void) {
9334 if (ufoMode
== UFO_MODE_NONE
) {
9337 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
9338 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
9340 ufoMode
= UFO_MODE_NATIVE
;
9344 while (ufoFileStackPos
!= 0) ufoPopInFile();
9348 //==========================================================================
9352 //==========================================================================
9353 void ufoRunFile (const char *fname
) {
9354 if (ufoMode
== UFO_MODE_NONE
) {
9357 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
9358 ufoMode
= UFO_MODE_NATIVE
;
9361 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
9363 FILE *ufl
= fopen(ufmname
, "rb");
9365 FILE *ufl
= fopen(ufmname
, "r");
9369 ufoSetInFileNameReuse(ufmname
);
9371 ufoFileId
= ufoLastUsedFileId
;
9372 setLastIncPath(ufoInFileName
, 0);
9375 ufoFatal("cannot load source file '%s'", fname
);
9377 ufoRunInterpretLoop();