UrForth: added some words for the address register manipulation; TYPE and others...
[urasm.git] / src / liburforth / urforth.c
blob3affccc497df30694a6c316c92d8b2d7334821a6
1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
3 // GPLv3 ONLY
4 #ifdef WIN32
5 #include <windows.h>
6 #endif
7 #include <stdarg.h>
8 #include <setjmp.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
18 #include "urforth.h"
20 #ifdef WIN32
21 # define realpath(shit,fuck) _fullpath(fuck, shit, 32768)
22 #endif
25 #define UFO_DEBUG_STARTUP_TIMES
26 //#define UFO_DEBUG_FATAL_ABORT
27 #define UFO_DEBUG_DEBUG /* ;-) */
28 //#define UFO_TRACE_VM_DOER
29 //#define UFO_TRACE_VM_RUN
30 //#define UFO_DEBUG_INCLUDE
31 //#define UFO_DEBUG_DUMP_NEW_HEADERS
32 //#define UFO_DEBUG_FIND_WORD
33 //#define UFO_DEBUG_FIND_WORD_IN_VOC
34 //#define UFO_DEBUG_FIND_WORD_COLON
36 // 2/8 msecs w/o inlining
37 // 1/5 msecs with inlining
38 #if 1
39 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
40 #else
41 # define UFO_FORCE_INLINE static __attribute__((noinline)) __attribute__((unused))
42 #endif
43 #define UFO_DISABLE_INLINE static __attribute__((noinline)) __attribute__((unused))
45 // detect arch, and use faster memory access code on x86
46 #if defined(__x86_64__) || defined(_M_X64) || \
47 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
48 # define UFO_FAST_MEM_ACCESS
49 #endif
51 // should not be bigger than this!
52 #define UFO_MAX_WORD_LENGTH (250)
54 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
57 // ////////////////////////////////////////////////////////////////////////// //
58 static const char *ufo_assert_failure (const char *cond, const char *fname, int fline, const char *func) {
59 for (const char *t = fname; *t; ++t) {
60 #ifdef WIN32
61 if (*t == '/' || *t == '\\') fname = t+1;
62 #else
63 if (*t == '/') fname = t+1;
64 #endif
66 fflush(NULL);
67 fprintf(stderr, "\n%s:%d: Assertion in `%s` failed: %s\n", fname, fline, func, cond);
68 fflush(NULL);
69 abort();
72 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
75 static char ufoRealPathBuf[32769];
76 static char ufoRealPathHashBuf[32769];
79 //==========================================================================
81 // ufoRealPath
83 //==========================================================================
84 static char *ufoRealPath (const char *fname) {
85 char *res;
86 if (fname != NULL && fname[0] != 0) {
87 res = realpath(fname, NULL);
88 if (res != NULL) {
89 const size_t slen = strlen(res);
90 if (slen < 32768) {
91 strcpy(ufoRealPathBuf, res);
92 free(res);
93 res = ufoRealPathBuf;
94 } else {
95 free(res);
96 res = NULL;
99 } else {
100 res = NULL;
102 return res;
106 #ifndef WIN32
107 static time_t secstart = 0;
108 #endif
112 //==========================================================================
114 // ufo_get_msecs
116 //==========================================================================
117 static uint64_t ufo_get_msecs (void) {
118 #ifdef WIN32
119 return GetTickCount();
120 #else
121 struct timespec ts;
122 #ifdef CLOCK_MONOTONIC
123 ufo_assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
124 #else
125 // this should be available everywhere
126 ufo_assert(clock_gettime(CLOCK_REALTIME, &ts) == 0);
127 #endif
128 // first run?
129 if (secstart == 0) {
130 secstart = ts.tv_sec+1;
131 ufo_assert(secstart); // it should not be zero
133 return (uint64_t)(ts.tv_sec-secstart+2)*1000U+(uint32_t)ts.tv_nsec/1000000U;
134 // nanoseconds
135 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
136 #endif
140 //==========================================================================
142 // joaatHashBuf
144 //==========================================================================
145 UFO_FORCE_INLINE uint32_t joaatHashBuf (const void *buf, size_t len, uint8_t orbyte) {
146 uint32_t hash = 0x29a;
147 const uint8_t *s = (const uint8_t *)buf;
148 while (len--) {
149 hash += (*s++)|orbyte;
150 hash += hash<<10;
151 hash ^= hash>>6;
153 // finalize
154 hash += hash<<3;
155 hash ^= hash>>11;
156 hash += hash<<15;
157 return hash;
161 // this converts ASCII capitals to locase (and destroys other, but who cares)
162 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
165 //==========================================================================
167 // toUpper
169 //==========================================================================
170 UFO_FORCE_INLINE char toUpper (char ch) {
171 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
175 //==========================================================================
177 // toUpperU8
179 //==========================================================================
180 UFO_FORCE_INLINE uint8_t toUpperU8 (uint8_t ch) {
181 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
185 //==========================================================================
187 // digitInBase
189 //==========================================================================
190 UFO_FORCE_INLINE int digitInBase (char ch, int base) {
191 switch (ch) {
192 case '0' ... '9': ch = ch - '0'; break;
193 case 'A' ... 'Z': ch = ch - 'A' + 10; break;
194 case 'a' ... 'z': ch = ch - 'a' + 10; break;
195 default: base = -1; break;
197 return (ch >= 0 && ch < base ? ch : -1);
202 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 ;; word header format:
204 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
205 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
206 ;; exact uppercase, only something that resembles it)
207 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
208 ;; before nfa, we have such "hidden" fields:
209 ;; dd dfa ; pointer to the debug data; can be 0 if debug info is missing
210 ;; dd xfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
211 ;; dd yfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
212 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
213 ;; ; if there is no hashtable, this field is not used
214 ;; lfa:
215 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
216 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
217 ;; nfa:
218 ;; dd flags-and-name-len ; see below
219 ;; db name ; no terminating zero or other "termination flag" here
220 ;; here could be some 0 bytes to align everything to 4 bytes
221 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
222 ;; ; full length, including padding, but not including this byte
223 ;; cfa:
224 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
225 ;; pfa:
226 ;; word data follows
228 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
229 ;; layout:
230 ;; db namelen
231 ;; db argtype
232 ;; dw flags
233 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
235 ;; flags:
236 ;; bit 0: immediate
237 ;; bit 1: smudge
238 ;; bit 2: noreturn
239 ;; bit 3: hidden
240 ;; bit 4: codeblock
241 ;; bit 5: vocabulary
242 ;; bit 6: *UNUSED* main scattered colon word (with "...")
243 ;; bit 7: protected
245 ;; argtype is the type of the argument that this word reads from the threaded code.
246 ;; possible argument types:
247 ;; 0: none
248 ;; 1: branch address
249 ;; 2: cell-size numeric literal
250 ;; 3: cell-counted string with terminating zero (not counted)
251 ;; 4: cfa of another word
252 ;; 5: cblock
253 ;; 6: vocid
254 ;; 7: byte-counted string with terminating zero (not counted)
255 ;; 8: *UNUSED* unsigned byte
256 ;; 9: *UNUSED* signed byte
257 ;; 10: *UNUSED* unsigned word
258 ;; 11: *UNUSED* signed word
261 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262 ;; wordlist structure (at PFA)
263 ;; -4: wordlist type id (used by structs, for example)
264 ;; dd latest
265 ;; dd voclink (voclink always points here)
266 ;; dd parent (if not zero, all parent words are visible)
267 ;; dd header-nfa (can be 0 for anonymous wordlists)
268 ;; hashtable (if enabled), or ~0U if no hash table
272 // ////////////////////////////////////////////////////////////////////////// //
273 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
274 #define UFO_LFA_TO_DFA(lfa_) ((lfa_) - 4u * 4u)
275 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
276 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
277 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
278 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
279 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
280 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
281 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
282 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
283 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
284 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
285 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
286 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
287 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
288 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
289 #define UFO_XFA_TO_WST(xfa_) ((xfa_) - 4u)
290 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 2u * 4u)
291 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
294 // ////////////////////////////////////////////////////////////////////////// //
295 //#define UFW_WARG_U8 (8u<<8)
296 //#define UFW_WARG_S8 (9u<<8)
297 //#define UFW_WARG_U16 (10u<<8)
298 //#define UFW_WARG_S16 (11u<<8)
300 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
301 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
302 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
303 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
304 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
306 #define UFO_HASHTABLE_SIZE (256)
308 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
310 #define UFO_MAX_NATIVE_CFAS (1024u)
311 static ufoNativeCFA *ufoForthCFAs = NULL;
312 static uint32_t ufoCFAsUsed = 0;
314 static uint32_t ufoDoForthCFA;
315 static uint32_t ufoDoVariableCFA;
316 static uint32_t ufoDoValueCFA;
317 static uint32_t ufoDoConstCFA;
318 static uint32_t ufoDoDeferCFA;
319 static uint32_t ufoDoVocCFA;
320 static uint32_t ufoDoCreateCFA;
321 static uint32_t ufoDoUserVariableCFA;
323 static uint32_t ufoStrLit8CFA;
325 // special address types:
326 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
327 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
329 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
330 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
331 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
332 #define UFO_ADDR_HANDLE_SHIFT (12)
333 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
335 // temporary area is 1MB buffer out of the main image
336 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
337 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
339 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
342 debug image stores mapping from dictionary addresses to source files and lines.
343 it is used for backtraces and debuggers, so it doesn't need to be optimised for
344 speed; therefore i choose to optimise it for size.
346 debug map format is this:
347 dv filename-len
348 ...filename...
349 align, so next data starts at 4-byte boundary
350 dxl line ; 0: no more lines
351 dxi ip-length
352 ...next filename record
354 "dv" is variable-length number. each byte uses bit 7 as "continuation" bit.
356 "dx?" is delta-coded number.
357 "dxi" is global, starts with 0, and incrementing.
358 "dxl" resets to 0 on each new file.
359 delta format is the same as "dv".
362 static uint32_t *ufoImage = NULL;
363 static uint32_t ufoImageSize = 0;
365 static uint8_t *ufoDebugImage = NULL;
366 static uint32_t ufoDebugImageUsed = 0;
367 static uint32_t ufoDebugImageSize = 0;
368 static uint32_t ufoDebugFileId = 0;
369 static uint32_t ufoDebugLastFRecAddr = 0;
370 static uint32_t ufoDebugCurrDP = 0;
372 static uint32_t ufoInRunWord = 0;
374 static volatile int ufoVMAbort = 0;
375 static volatile int ufoVMStop = 0;
377 #define ufoTrueValue (~(uint32_t)0)
379 enum {
380 UFO_MODE_NONE = -1,
381 UFO_MODE_NATIVE = 0, // executing forth code
382 UFO_MODE_MACRO = 1, // executing forth asm macro
384 static uint32_t ufoMode = UFO_MODE_NONE;
386 #define UFO_DSTACK_SIZE (8192)
387 #define UFO_RSTACK_SIZE (4096)
388 #define UFO_LSTACK_SIZE (4096)
389 #define UFO_MAX_TASK_NAME (127)
391 // to support multitasking (required for the debugger),
392 // our virtual machine state is encapsulated in a struct.
393 typedef struct UfoState_t {
394 uint32_t id;
395 uint32_t dStack[UFO_DSTACK_SIZE];
396 uint32_t rStack[UFO_RSTACK_SIZE];
397 uint32_t lStack[UFO_LSTACK_SIZE];
398 uint32_t IP; // in image
399 uint32_t SP; // points AFTER the last value pushed
400 uint32_t RP; // points AFTER the last value pushed
401 uint32_t RPTop; // stop when RP is this
402 // address register
403 uint32_t regA;
404 // for locals
405 uint32_t LP;
406 uint32_t LBP;
407 uint32_t vmRPopCFA;
408 // temp image
409 uint32_t *imageTemp;
410 uint32_t imageTempSize;
411 // linked list of all allocated states (tasks)
412 char name[UFO_MAX_TASK_NAME + 1];
413 } UfoState;
415 // 'cmon!
416 #define UFO_MAX_STATES (8192)
418 // this is indexed by id
419 static UfoState *ufoStateMap[UFO_MAX_STATES] = {NULL};
420 static uint32_t ufoStateUsedBitmap[UFO_MAX_STATES/32] = {0};
422 // currently active execution state
423 static UfoState *ufoCurrState = NULL;
424 // state we're yielded from
425 static UfoState *ufoYieldedState = NULL;
426 // if debug state is not NULL, VM will switch to it
427 // after executing one instruction from the current state.
428 // it will store current state in `ufoDebugeeState`.
429 static UfoState *ufoDebuggerState = NULL;
430 static uint32_t ufoSingleStep = 0;
432 #define ufoDStack (ufoCurrState->dStack)
433 #define ufoRStack (ufoCurrState->rStack)
434 #define ufoLStack (ufoCurrState->lStack)
435 #define ufoIP (ufoCurrState->IP)
436 #define ufoSP (ufoCurrState->SP)
437 #define ufoRP (ufoCurrState->RP)
438 #define ufoRPTop (ufoCurrState->RPTop)
439 #define ufoLP (ufoCurrState->LP)
440 #define ufoLBP (ufoCurrState->LBP)
441 #define ufoRegA (ufoCurrState->regA)
442 #define ufoImageTemp (ufoCurrState->imageTemp)
443 #define ufoImageTempSize (ufoCurrState->imageTempSize)
444 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
446 // 256 bytes for user variables
447 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
448 #define UFO_USER_AREA_SIZE (256u)
449 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
450 #define UFO_NBUF_SIZE (256u)
451 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
452 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
454 // dynamically allocated text input buffer
455 // always ends with zero (this is word name too)
456 static const uint32_t ufoAddrTIBx = UFO_ADDR_TEMP_BIT + 0u * 4u; // TIB
457 static const uint32_t ufoAddrINx = UFO_ADDR_TEMP_BIT + 1u * 4u; // >IN
458 static const uint32_t ufoAddrDefTIB = UFO_ADDR_TEMP_BIT + 2u * 4u; // default TIB (handle); user cannot change it
459 static const uint32_t ufoAddrBASE = UFO_ADDR_TEMP_BIT + 3u * 4u;
460 static const uint32_t ufoAddrUserVarUsed = UFO_ADDR_TEMP_BIT + 4u * 4u;
462 static uint32_t ufoAddrContext; // CONTEXT
463 static uint32_t ufoAddrCurrent; // CURRENT (definitions will go there)
464 static uint32_t ufoAddrSTATE;
465 static uint32_t ufoAddrVocLink;
466 static uint32_t ufoAddrDP;
467 static uint32_t ufoAddrDPTemp;
468 static uint32_t ufoAddrNewWordFlags;
469 static uint32_t ufoAddrRedefineWarning;
470 static uint32_t ufoAddrLastXFA;
472 // allows to redefine even protected words
473 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
474 // do not warn about ordinary words, allow others
475 #define UFO_REDEF_WARN_NONE (0)
476 // do warn
477 #define UFO_REDEF_WARN_NORMAL (1)
479 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
480 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
482 #define UFO_MAX_NESTED_INCLUDES (32)
483 typedef struct {
484 FILE *fl;
485 char *fname;
486 char *incpath;
487 char *sysincpath;
488 int fline;
489 uint32_t id; // non-zero unique id
490 } UFOFileStackEntry;
492 static UFOFileStackEntry ufoFileStack[UFO_MAX_NESTED_INCLUDES];
493 static uint32_t ufoFileStackPos; // after the last used item
495 static FILE *ufoInFile = NULL;
496 static char *ufoInFileName = NULL;
497 static char *ufoLastIncPath = NULL;
498 static char *ufoLastSysIncPath = NULL;
499 static int ufoInFileLine = 0;
500 static uint32_t ufoFileId = 0;
501 static uint32_t ufoLastUsedFileId = 0;
503 static int ufoLastEmitWasCR = 1;
505 #define UFO_VOCSTACK_SIZE (16u)
506 static uint32_t ufoVocStack[UFO_VOCSTACK_SIZE]; // cfas
507 static uint32_t ufoVSP;
508 static uint32_t ufoForthVocId;
509 static uint32_t ufoCompilerVocId;
511 // dynamic handles
512 typedef struct UHandleInfo_t {
513 uint32_t ufoHandle;
514 uint32_t typeid;
515 uint8_t *data;
516 uint32_t size;
517 uint32_t used;
518 // in free list
519 struct UHandleInfo_t *next;
520 } UfoHandle;
522 static UfoHandle *ufoHandleFreeList = NULL;
523 static UfoHandle **ufoHandles = NULL;
524 static uint32_t ufoHandlesUsed = 0;
525 static uint32_t ufoHandlesAlloted = 0;
527 #define UFO_HANDLE_FREE (~(uint32_t)0)
529 static char ufoCurrFileLine[520];
531 // for `ufoFatal()`
532 static uint32_t ufoInBacktrace = 0;
535 // ////////////////////////////////////////////////////////////////////////// //
536 static void ufoClearCondDefines (void);
538 static void ufoRunVMCFA (uint32_t cfa);
540 static void ufoBacktrace (uint32_t ip);
542 static void ufoClearCondDefines (void);
544 static UfoState *ufoNewState (uint32_t cfa);
545 static void ufoInitStateUserVars (UfoState *st, int initial);
546 static void ufoFreeState (UfoState *st);
547 static UfoState *ufoFindState (uint32_t stid);
548 static void ufoSwitchToState (UfoState *newst);
550 __attribute__((unused)) static void ufoDumpWordHeader (const uint32_t lfa);
552 #ifndef WIN32
553 static void ufoDisableRaw (void);
554 #endif
556 #ifdef UFO_DEBUG_DEBUG
557 static void ufoDumpDebugImage (void);
558 #endif
561 // ////////////////////////////////////////////////////////////////////////// //
562 #define UFWORD(name_) \
563 static void ufoWord_##name_ (uint32_t mypfa)
565 #define UFCALL(name_) ufoWord_##name_(0)
566 #define UFCFA(name_) (&ufoWord_##name_)
568 // for TIB words
569 UFWORD(CPEEK_REGA_IDX);
570 UFWORD(CPOKE_REGA_IDX);
572 // for peek and poke
573 UFWORD(PAR_HANDLE_LOAD_BYTE);
574 UFWORD(PAR_HANDLE_LOAD_WORD);
575 UFWORD(PAR_HANDLE_LOAD_CELL);
576 UFWORD(PAR_HANDLE_STORE_BYTE);
577 UFWORD(PAR_HANDLE_STORE_WORD);
578 UFWORD(PAR_HANDLE_STORE_CELL);
581 //==========================================================================
583 // ufoSetUserAbort
585 //==========================================================================
586 void ufoSetUserAbort (void) {
587 ufoVMAbort = 1;
591 //==========================================================================
593 // ufoAllocHandle
595 //==========================================================================
596 static UfoHandle *ufoAllocHandle (uint32_t typeid) {
597 ufo_assert(typeid != UFO_HANDLE_FREE);
598 UfoHandle *newh = ufoHandleFreeList;
599 if (newh == NULL) {
600 if (ufoHandlesUsed == ufoHandlesAlloted) {
601 uint32_t newsz = ufoHandlesAlloted + 16384;
602 // due to offsets, this is the maximum number of handles we can have
603 if (newsz > 0x1ffffU) {
604 if (ufoHandlesAlloted > 0x1ffffU) ufoFatal("too many dynamic handles");
605 newsz = 0x1ffffU + 1U;
606 ufo_assert(newsz > ufoHandlesAlloted);
608 UfoHandle **nh = realloc(ufoHandles, sizeof(ufoHandles[0]) * newsz);
609 if (nh == NULL) ufoFatal("out of memory for handle table");
610 ufoHandles = nh;
611 ufoHandlesAlloted = newsz;
613 newh = calloc(1, sizeof(UfoHandle));
614 if (newh == NULL) ufoFatal("out of memory for handle info");
615 ufoHandles[ufoHandlesUsed] = newh;
616 // setup new handle info
617 newh->ufoHandle = (ufoHandlesUsed << UFO_ADDR_HANDLE_SHIFT) | UFO_ADDR_HANDLE_BIT;
618 ufoHandlesUsed += 1;
619 } else {
620 ufo_assert(newh->typeid == UFO_HANDLE_FREE);
621 ufoHandleFreeList = newh->next;
623 // setup new handle info
624 newh->typeid = typeid;
625 newh->data = NULL;
626 newh->size = 0;
627 newh->used = 0;
628 newh->next = NULL;
629 return newh;
633 //==========================================================================
635 // ufoFreeHandle
637 //==========================================================================
638 static void ufoFreeHandle (UfoHandle *hh) {
639 if (hh != NULL) {
640 ufo_assert(hh->typeid != UFO_HANDLE_FREE);
641 if (hh->data) free(hh->data);
642 hh->typeid = UFO_HANDLE_FREE;
643 hh->data = NULL;
644 hh->size = 0;
645 hh->used = 0;
646 hh->next = ufoHandleFreeList;
647 ufoHandleFreeList = hh;
652 //==========================================================================
654 // ufoGetHandle
656 //==========================================================================
657 static UfoHandle *ufoGetHandle (uint32_t hh) {
658 UfoHandle *res;
659 if (hh != 0 && (hh & UFO_ADDR_HANDLE_BIT) != 0) {
660 hh = (hh & UFO_ADDR_HANDLE_MASK) >> UFO_ADDR_HANDLE_SHIFT;
661 if (hh < ufoHandlesUsed) {
662 res = ufoHandles[hh];
663 if (res->typeid == UFO_HANDLE_FREE) res = NULL;
664 } else {
665 res = NULL;
667 } else {
668 res = NULL;
670 return res;
674 //==========================================================================
676 // setLastIncPath
678 //==========================================================================
679 static void setLastIncPath (const char *fname, int system) {
680 if (fname == NULL || fname[0] == 0) {
681 if (system) {
682 if (ufoLastSysIncPath) free(ufoLastIncPath);
683 ufoLastSysIncPath = NULL;
684 } else {
685 if (ufoLastIncPath) free(ufoLastIncPath);
686 ufoLastIncPath = strdup(".");
688 } else {
689 char *lslash;
690 char *cpos;
691 if (system) {
692 if (ufoLastSysIncPath) free(ufoLastSysIncPath);
693 ufoLastSysIncPath = strdup(fname);
694 lslash = ufoLastSysIncPath;
695 cpos = ufoLastSysIncPath;
696 } else {
697 if (ufoLastIncPath) free(ufoLastIncPath);
698 ufoLastIncPath = strdup(fname);
699 lslash = ufoLastIncPath;
700 cpos = ufoLastIncPath;
702 while (*cpos) {
703 #ifdef WIN32
704 if (*cpos == '/' || *cpos == '\\') lslash = cpos;
705 #else
706 if (*cpos == '/') lslash = cpos;
707 #endif
708 cpos += 1;
710 *lslash = 0;
715 //==========================================================================
717 // ufoClearIncludePath
719 // required for UrAsm
721 //==========================================================================
722 void ufoClearIncludePath (void) {
723 if (ufoLastIncPath != NULL) {
724 free(ufoLastIncPath);
725 ufoLastIncPath = NULL;
727 if (ufoLastSysIncPath != NULL) {
728 free(ufoLastSysIncPath);
729 ufoLastSysIncPath = NULL;
734 //==========================================================================
736 // ufoErrorPrintFile
738 //==========================================================================
739 static void ufoErrorPrintFile (FILE *fo) {
740 if (ufoInFileName) {
741 fprintf(fo, "UFO ERROR at file %s, line %d: ", ufoInFileName, ufoInFileLine);
742 } else {
743 fprintf(fo, "UFO ERROR somewhere in time: ");
748 //==========================================================================
750 // ufoErrorMsgV
752 //==========================================================================
753 static void ufoErrorMsgV (const char *fmt, va_list ap) {
754 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
755 fflush(stdout);
756 ufoErrorPrintFile(stderr);
757 vfprintf(stderr, fmt, ap);
758 va_end(ap);
759 fputc('\n', stderr);
760 fflush(NULL);
764 //==========================================================================
766 // ufoWarning
768 //==========================================================================
769 __attribute__((format(printf, 1, 2)))
770 void ufoWarning (const char *fmt, ...) {
771 va_list ap;
772 va_start(ap, fmt);
773 ufoErrorMsgV(fmt, ap);
777 //==========================================================================
779 // ufoFatal
781 //==========================================================================
782 __attribute__((noreturn)) __attribute__((format(printf, 1, 2)))
783 void ufoFatal (const char *fmt, ...) {
784 va_list ap;
785 #ifndef WIN32
786 ufoDisableRaw();
787 #endif
788 va_start(ap, fmt);
789 ufoErrorMsgV(fmt, ap);
790 if (!ufoInBacktrace) {
791 ufoInBacktrace = 1;
792 ufoBacktrace(ufoIP);
793 ufoInBacktrace = 0;
794 } else {
795 fprintf(stderr, "DOUBLE FATAL: error in backtrace!\n");
796 abort();
798 #ifdef UFO_DEBUG_FATAL_ABORT
799 abort();
800 #endif
801 ufoFatalError();
805 // ////////////////////////////////////////////////////////////////////////// //
806 // working with the stacks
807 UFO_FORCE_INLINE void ufoPush (uint32_t v) { if (ufoSP >= UFO_DSTACK_SIZE) ufoFatal("data stack overflow"); ufoDStack[ufoSP++] = v; }
808 UFO_FORCE_INLINE void ufoDrop (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); --ufoSP; }
809 UFO_FORCE_INLINE uint32_t ufoPop (void) { if (ufoSP == 0) { ufoFatal("data stack underflow"); } return ufoDStack[--ufoSP]; }
810 UFO_FORCE_INLINE uint32_t ufoPeek (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); return ufoDStack[ufoSP-1u]; }
811 UFO_FORCE_INLINE void ufoDup (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack[ufoSP-1u]); }
812 UFO_FORCE_INLINE void ufoOver (void) { if (ufoSP < 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack[ufoSP-2u]); }
813 UFO_FORCE_INLINE void ufoSwap (void) { if (ufoSP < 2u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = t; }
814 UFO_FORCE_INLINE void ufoRot (void) { if (ufoSP < 3u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-3u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = t; }
815 UFO_FORCE_INLINE void ufoNRot (void) { if (ufoSP < 3u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-3u] = t; }
817 UFO_FORCE_INLINE void ufo2Dup (void) { ufoOver(); ufoOver(); }
818 UFO_FORCE_INLINE void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
819 UFO_FORCE_INLINE void ufo2Over (void) { if (ufoSP < 4u) ufoFatal("data stack underflow"); const uint32_t n0 = ufoDStack[ufoSP-4u]; const uint32_t n1 = ufoDStack[ufoSP-3u]; ufoPush(n0); ufoPush(n1); }
820 UFO_FORCE_INLINE void ufo2Swap (void) { if (ufoSP < 4u) ufoFatal("data stack underflow"); const uint32_t n0 = ufoDStack[ufoSP-4u]; const uint32_t n1 = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-4u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-3u] = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-2u] = n0; ufoDStack[ufoSP-1u] = n1; }
822 UFO_FORCE_INLINE void ufoRPush (uint32_t v) { if (ufoRP >= UFO_RSTACK_SIZE) ufoFatal("return stack overflow"); ufoRStack[ufoRP++] = v; }
823 UFO_FORCE_INLINE void ufoRDrop (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); --ufoRP; }
824 UFO_FORCE_INLINE uint32_t ufoRPop (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); return ufoRStack[--ufoRP]; }
825 UFO_FORCE_INLINE uint32_t ufoRPeek (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); return ufoRStack[ufoRP-1u]; }
826 UFO_FORCE_INLINE void ufoRDup (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); ufoPush(ufoRStack[ufoRP-1u]); }
828 UFO_FORCE_INLINE void ufoPushBool (int v) { ufoPush(v ? ufoTrueValue : 0u); }
831 //==========================================================================
833 // ufoImgEnsureSize
835 //==========================================================================
836 static void ufoImgEnsureSize (uint32_t addr) {
837 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) != 0) ufoFatal("ufoImgEnsureSize: internal error");
838 if (addr >= ufoImageSize) {
839 // 64MB should be enough for everyone!
840 if (addr >= 0x04000000U) {
841 ufoFatal("image grown too big (addr=0%08XH)", addr);
843 const const uint32_t osz = ufoImageSize;
844 // grow by 1MB steps
845 const uint32_t nsz = (addr|0x000fffffU) + 1U;
846 ufo_assert(nsz > addr);
847 uint32_t *nimg = realloc(ufoImage, nsz);
848 if (nimg == NULL) {
849 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
850 ufoImageSize / 1024u / 1024u,
851 nsz / 1024u / 1024u);
853 ufoImage = nimg;
854 ufoImageSize = nsz;
855 memset((char *)ufoImage + osz, 0, (nsz - osz));
860 //==========================================================================
862 // ufoImgEnsureTemp
864 //==========================================================================
865 static void ufoImgEnsureTemp (uint32_t addr) {
866 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
867 if (addr >= ufoImageTempSize) {
868 if (addr >= 1024u * 1024u) {
869 ufoFatal("Forth segmentation fault at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
871 const uint32_t osz = ufoImageTempSize;
872 // grow by 8KB steps
873 const uint32_t nsz = (addr|0x00001fffU) + 1U;
874 uint32_t *nimg = realloc(ufoImageTemp, nsz);
875 if (nimg == NULL) {
876 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
877 ufoImageTempSize / 1024u,
878 nsz / 1024u);
880 ufoImageTemp = nimg;
881 ufoImageTempSize = nsz;
882 memset((char *)ufoImageTemp + osz, 0, (nsz - osz));
887 #ifdef UFO_FAST_MEM_ACCESS
888 //==========================================================================
890 // ufoImgPutU8
892 // fast
894 //==========================================================================
895 UFO_FORCE_INLINE void ufoImgPutU8 (uint32_t addr, const uint32_t value) {
896 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
897 if (addr >= ufoImageSize) ufoImgEnsureSize(addr);
898 *((uint8_t *)ufoImage + addr) = (uint8_t)value;
899 } else if (addr & UFO_ADDR_TEMP_BIT) {
900 addr &= UFO_ADDR_TEMP_MASK;
901 if (addr >= ufoImageTempSize) ufoImgEnsureTemp(addr);
902 *((uint8_t *)ufoImageTemp + addr) = (uint8_t)value;
903 } else {
904 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
909 //==========================================================================
911 // ufoImgPutU16
913 // fast
915 //==========================================================================
916 UFO_FORCE_INLINE void ufoImgPutU16 (uint32_t addr, const uint32_t value) {
917 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
918 if (addr + 1u >= ufoImageSize) ufoImgEnsureSize(addr + 1u);
919 *(uint16_t *)((uint8_t *)ufoImage + addr) = (uint16_t)value;
920 } else if (addr & UFO_ADDR_TEMP_BIT) {
921 addr &= UFO_ADDR_TEMP_MASK;
922 if (addr + 1u >= ufoImageTempSize) ufoImgEnsureTemp(addr + 1u);
923 *(uint16_t *)((uint8_t *)ufoImageTemp + addr) = (uint16_t)value;
924 } else {
925 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
930 //==========================================================================
932 // ufoImgPutU32
934 // fast
936 //==========================================================================
937 UFO_FORCE_INLINE void ufoImgPutU32 (uint32_t addr, const uint32_t value) {
938 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
939 if (addr + 3u >= ufoImageSize) ufoImgEnsureSize(addr + 3u);
940 *(uint32_t *)((uint8_t *)ufoImage + addr) = value;
941 } else if (addr & UFO_ADDR_TEMP_BIT) {
942 addr &= UFO_ADDR_TEMP_MASK;
943 if (addr + 3u >= ufoImageTempSize) ufoImgEnsureTemp(addr + 3u);
944 *(uint32_t *)((uint8_t *)ufoImageTemp + addr) = value;
945 } else {
946 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
951 //==========================================================================
953 // ufoImgGetU8
955 // false
957 //==========================================================================
958 UFO_FORCE_INLINE uint32_t ufoImgGetU8 (uint32_t addr) {
959 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
960 if (addr >= ufoImageSize) {
961 // accessing unallocated image area is segmentation fault
962 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
964 return *((const uint8_t *)ufoImage + addr);
965 } else if (addr & UFO_ADDR_TEMP_BIT) {
966 addr &= UFO_ADDR_TEMP_MASK;
967 if (addr >= ufoImageTempSize) {
968 // accessing unallocated image area is segmentation fault
969 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
971 return *((const uint8_t *)ufoImageTemp + addr);
972 } else {
973 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
978 //==========================================================================
980 // ufoImgGetU16
982 // fast
984 //==========================================================================
985 UFO_FORCE_INLINE uint32_t ufoImgGetU16 (uint32_t addr) {
986 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
987 if (addr + 1u >= ufoImageSize) {
988 // accessing unallocated image area is segmentation fault
989 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
991 return *(const uint16_t *)((const uint8_t *)ufoImage + addr);
992 } else if (addr & UFO_ADDR_TEMP_BIT) {
993 addr &= UFO_ADDR_TEMP_MASK;
994 if (addr + 1u >= ufoImageTempSize) {
995 // accessing unallocated image area is segmentation fault
996 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
998 return *(const uint16_t *)((const uint8_t *)ufoImageTemp + addr);
999 } else {
1000 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1005 //==========================================================================
1007 // ufoImgGetU32
1009 // fast
1011 //==========================================================================
1012 UFO_FORCE_INLINE uint32_t ufoImgGetU32 (uint32_t addr) {
1013 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1014 if (addr + 3u >= ufoImageSize) {
1015 // accessing unallocated image area is segmentation fault
1016 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
1018 return *(const uint32_t *)((const uint8_t *)ufoImage + addr);
1019 } else if (addr & UFO_ADDR_TEMP_BIT) {
1020 addr &= UFO_ADDR_TEMP_MASK;
1021 if (addr + 3u >= ufoImageTempSize) {
1022 // accessing unallocated image area is segmentation fault
1023 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
1025 return *(const uint32_t *)((const uint8_t *)ufoImageTemp + addr);
1026 } else {
1027 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1031 #else
1033 //==========================================================================
1035 // ufoImgPutU8
1037 // general
1039 //==========================================================================
1040 UFO_FORCE_INLINE void ufoImgPutU8 (uint32_t addr, const uint32_t value) {
1041 uint32_t *imgptr;
1042 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1043 if (addr >= ufoImageSize) ufoImgEnsureSize(addr);
1044 imgptr = &ufoImage[addr/4u];
1045 } else if (addr & UFO_ADDR_TEMP_BIT) {
1046 addr &= UFO_ADDR_TEMP_MASK;
1047 if (addr >= ufoImageTempSize) ufoImgEnsureTemp(addr);
1048 imgptr = &ufoImageTemp[addr/4u];
1049 } else {
1050 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1052 const uint8_t val = (uint8_t)value;
1053 memcpy((uint8_t *)imgptr + (addr&3), &val, 1);
1057 //==========================================================================
1059 // ufoImgPutU16
1061 // general
1063 //==========================================================================
1064 UFO_FORCE_INLINE void ufoImgPutU16 (uint32_t addr, const uint32_t value) {
1065 ufoImgPutU8(addr, value&0xffU);
1066 ufoImgPutU8(addr + 1u, (value>>8)&0xffU);
1070 //==========================================================================
1072 // ufoImgPutU32
1074 // general
1076 //==========================================================================
1077 UFO_FORCE_INLINE void ufoImgPutU32 (uint32_t addr, const uint32_t value) {
1078 ufoImgPutU16(addr, value&0xffffU);
1079 ufoImgPutU16(addr + 2u, (value>>16)&0xffffU);
1083 //==========================================================================
1085 // ufoImgGetU8
1087 // general
1089 //==========================================================================
1090 UFO_FORCE_INLINE uint32_t ufoImgGetU8 (uint32_t addr) {
1091 uint32_t *imgptr;
1092 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1093 if (addr >= ufoImageSize) return 0;
1094 imgptr = &ufoImage[addr/4u];
1095 } else if (addr & UFO_ADDR_TEMP_BIT) {
1096 addr &= UFO_ADDR_TEMP_MASK;
1097 if (addr >= ufoImageTempSize) return 0;
1098 imgptr = &ufoImageTemp[addr/4u];
1099 } else {
1100 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1102 uint8_t val;
1103 memcpy(&val, (uint8_t *)imgptr + (addr&3), 1);
1104 return (uint32_t)val;
1108 //==========================================================================
1110 // ufoImgGetU16
1112 // general
1114 //==========================================================================
1115 UFO_FORCE_INLINE uint32_t ufoImgGetU16 (uint32_t addr) {
1116 return ufoImgGetU8(addr) | (ufoImgGetU8(addr + 1u) << 8);
1120 //==========================================================================
1122 // ufoImgGetU32
1124 // general
1126 //==========================================================================
1127 UFO_FORCE_INLINE uint32_t ufoImgGetU32 (uint32_t addr) {
1128 return ufoImgGetU16(addr) | (ufoImgGetU16(addr + 2u) << 16);
1130 #endif
1133 //==========================================================================
1135 // ufoEnsureDebug
1137 //==========================================================================
1138 UFO_DISABLE_INLINE void ufoEnsureDebug (uint32_t sdelta) {
1139 ufo_assert(sdelta != 0);
1140 if (ufoDebugImageUsed != 0) {
1141 if (ufoDebugImageUsed + sdelta >= 0x40000000U) ufoFatal("debug info too big");
1142 if (ufoDebugImageUsed + sdelta > ufoDebugImageSize) {
1143 // grow by 32KB, this should be more than enough
1144 const uint32_t newsz = ((ufoDebugImageUsed + sdelta) | 0x7fffU) + 1u;
1145 uint8_t *ndb = realloc(ufoDebugImage, newsz);
1146 if (ndb == NULL) ufoFatal("out of memory for debug info");
1147 ufoDebugImage = ndb;
1148 ufoDebugImageSize = newsz;
1150 } else {
1151 // initial allocation: 32KB, quite a lot
1152 ufoDebugImageSize = 1024 * 32;
1153 ufoDebugImage = malloc(ufoDebugImageSize);
1154 if (ufoDebugImage == NULL) ufoFatal("out of memory for debug info");
1159 #ifdef UFO_DEBUG_DEBUG
1160 //==========================================================================
1162 // ufoDumpDebugInfo
1164 //==========================================================================
1165 static void ufoDumpDebugImage (void) {
1166 #if 0
1167 uint32_t dbgpos = 0u; // first item is always "next file record"
1168 while (dbgpos < ufoDebugImageUsed) {
1169 const uint32_t ln = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1170 if (ln == ~(uint32_t)0) {
1171 // next file record
1172 const uint32_t nlen = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1173 fprintf(stderr, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage + dbgpos));
1174 dbgpos += nlen + 1u;
1175 if ((dbgpos & 0x03) != 0) dbgpos = (dbgpos | 0x03u) + 1u;
1176 } else {
1177 const uint32_t edp = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1178 fprintf(stderr, " line %6u: edp=%u\n", ln, edp);
1181 #endif
1183 #endif
1186 #define UFO_DBG_PUT_U4(val_) do { \
1187 const uint32_t vv_ = (val_); \
1188 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1189 ufoDebugImageUsed += 4u; \
1190 } while (0)
1192 //==========================================================================
1194 // ufoRecordDebug
1196 //==========================================================================
1197 UFO_DISABLE_INLINE void ufoRecordDebug (uint32_t newhere) {
1198 if (newhere > ufoDebugCurrDP) {
1199 if (ufoInFileName != NULL) {
1200 // check if we're doing the same file
1201 const uint32_t slen = (uint32_t)strlen(ufoInFileName);
1202 const int newfrec = (ufoDebugLastFRecAddr == 0) ||
1203 (*((const uint32_t *)(ufoDebugImage + ufoDebugLastFRecAddr)) != slen) ||
1204 (memcmp((const char *)ufoDebugImage + ufoDebugLastFRecAddr + 4u, ufoInFileName, slen) != 0);
1205 uint32_t fline = (uint32_t)ufoInFileLine;
1206 if (fline == ~(uint32_t)0) fline -= 1u;
1207 if (newfrec) {
1208 ufoEnsureDebug(slen + 4u + 4u + 4u + 32u); // way too much ;-)
1209 // finish previous record
1210 UFO_DBG_PUT_U4(~(uint32_t)0);
1211 // create new file record
1212 ufoDebugLastFRecAddr = ufoDebugImageUsed;
1213 UFO_DBG_PUT_U4(slen);
1214 memcpy(ufoDebugImage + ufoDebugImageUsed, ufoInFileName, slen + 1u);
1215 ufoDebugImageUsed += slen + 1u;
1216 while ((ufoDebugImageUsed & 0x03u) != 0) {
1217 ufoDebugImage[ufoDebugImageUsed] = 0;
1218 ufoDebugImageUsed += 1;
1220 UFO_DBG_PUT_U4(fline);
1221 UFO_DBG_PUT_U4(newhere);
1222 } else {
1223 // check if the line is the same
1224 if (*((const uint32_t *)(ufoDebugImage + ufoDebugImageUsed - 8u)) == fline) {
1225 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed - 4u)) = newhere;
1226 } else {
1227 // new line
1228 ufoEnsureDebug(8u);
1229 UFO_DBG_PUT_U4(fline);
1230 UFO_DBG_PUT_U4(newhere);
1233 } else {
1234 // we don't have a file, don't record debug info
1235 ufoDebugFileId = 0;
1236 ufoDebugLastFRecAddr = 0;
1238 ufoDebugCurrDP = newhere;
1243 //==========================================================================
1245 // ufoGetWordEndAddrYFA
1247 //==========================================================================
1248 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa) {
1249 if (yfa > 8u) {
1250 const uint32_t oyfa = yfa;
1251 yfa = ufoImgGetU32(yfa);
1252 if (yfa == 0) {
1253 if ((oyfa & UFO_ADDR_TEMP_BIT) == 0) {
1254 yfa = UFO_GET_DP();
1255 if ((yfa & UFO_ADDR_TEMP_BIT) != 0) {
1256 yfa = UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa)));
1258 } else {
1259 yfa = UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa)));
1261 } else {
1262 yfa = UFO_YFA_TO_WST(yfa);
1264 } else {
1265 yfa = 0;
1267 return yfa;
1271 //==========================================================================
1273 // ufoGetWordEndAddr
1275 //==========================================================================
1276 static uint32_t ufoGetWordEndAddr (const uint32_t cfa) {
1277 if (cfa != 0) {
1278 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa)));
1279 } else {
1280 return 0;
1285 //==========================================================================
1287 // ufoFindWordForIP
1289 // return NFA or 0
1291 // WARNING: this is SLOW!
1293 //==========================================================================
1294 static uint32_t ufoFindWordForIP (const uint32_t ip) {
1295 uint32_t res = 0;
1296 if (ip != 0) {
1297 // iterate over all words
1298 uint32_t xfa = ufoImgGetU32(ufoAddrLastXFA);
1299 if (xfa != 0) {
1300 while (res == 0 && xfa != 0) {
1301 const uint32_t yfa = UFO_XFA_TO_YFA(xfa);
1302 const uint32_t wst = UFO_YFA_TO_WST(yfa);
1303 const uint32_t wend = ufoGetWordEndAddrYFA(yfa);
1304 if (ip >= wst && ip < wend) {
1305 res = UFO_YFA_TO_NFA(yfa);
1306 } else {
1307 xfa = ufoImgGetU32(xfa);
1312 return res;
1316 //==========================================================================
1318 // ufoFindFileForIP
1320 // return file name or `NULL`
1322 // WARNING: this is SLOW!
1324 //==========================================================================
1325 static const char *ufoFindFileForIP (uint32_t ip, uint32_t *line) {
1326 const char *res = NULL;
1327 if (ip != 0 && ufoDebugImageUsed != 0) {
1328 uint32_t lastfinfo = 0u;
1329 uint32_t lastip = 0u;
1330 uint32_t dbgpos = 0u; // first item is always "next file record"
1331 while (res == NULL && dbgpos < ufoDebugImageUsed) {
1332 const uint32_t ln = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1333 if (ln == ~(uint32_t)0) {
1334 // next file record
1335 lastfinfo = dbgpos;
1336 const uint32_t nlen = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1337 dbgpos += nlen + 1u;
1338 if ((dbgpos & 0x03) != 0) dbgpos = (dbgpos | 0x03u) + 1u;
1339 } else {
1340 const uint32_t edp = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1341 if (ip >= lastip && ip < edp) {
1342 if (line) *line = ln;
1343 res = (const char *)(ufoDebugImage + lastfinfo + 4u);
1345 lastip = edp;
1349 return res;
1353 //==========================================================================
1355 // ufoBumpDP
1357 //==========================================================================
1358 UFO_FORCE_INLINE void ufoBumpDP (uint32_t delta) {
1359 uint32_t dp = ufoImgGetU32(ufoAddrDPTemp);
1360 if (dp == 0) {
1361 dp = ufoImgGetU32(ufoAddrDP);
1362 if ((dp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(dp + delta);
1363 dp += delta;
1364 ufoImgPutU32(ufoAddrDP, dp);
1365 } else {
1366 dp = ufoImgGetU32(ufoAddrDPTemp);
1367 if ((dp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(dp + delta);
1368 dp += delta;
1369 ufoImgPutU32(ufoAddrDPTemp, dp);
1374 //==========================================================================
1376 // ufoImgEmitU8
1378 //==========================================================================
1379 UFO_FORCE_INLINE void ufoImgEmitU8 (uint32_t value) {
1380 ufoImgPutU8(UFO_GET_DP(), value);
1381 ufoBumpDP(1);
1385 //==========================================================================
1387 // ufoImgEmitU32
1389 //==========================================================================
1390 UFO_FORCE_INLINE void ufoImgEmitU32 (uint32_t value) {
1391 ufoImgPutU32(UFO_GET_DP(), value);
1392 ufoBumpDP(4);
1396 #ifdef UFO_FAST_MEM_ACCESS
1398 //==========================================================================
1400 // ufoImgEmitU32_NoInline
1402 // false
1404 //==========================================================================
1405 UFO_FORCE_INLINE void ufoImgEmitU32_NoInline (uint32_t value) {
1406 ufoImgPutU32(UFO_GET_DP(), value);
1407 ufoBumpDP(4);
1410 #else
1412 //==========================================================================
1414 // ufoImgEmitU32_NoInline
1416 // general
1418 //==========================================================================
1419 UFO_DISABLE_INLINE void ufoImgEmitU32_NoInline (uint32_t value) {
1420 ufoImgPutU32(UFO_GET_DP(), value);
1421 ufoBumpDP(4);
1424 #endif
1427 //==========================================================================
1429 // ufoImgGetU8Ext
1431 // this understands handle addresses
1433 //==========================================================================
1434 UFO_FORCE_INLINE uint32_t ufoImgGetU8Ext (uint32_t addr) {
1435 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
1436 return ufoImgGetU8(addr);
1437 } else {
1438 ufoPush(0);
1439 ufoPush(addr);
1440 UFCALL(PAR_HANDLE_LOAD_BYTE);
1441 return ufoPop();
1446 //==========================================================================
1448 // ufoImgPutU8Ext
1450 // this understands handle addresses
1452 //==========================================================================
1453 UFO_FORCE_INLINE void ufoImgPutU8Ext (uint32_t addr, uint32_t value) {
1454 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
1455 ufoImgPutU8(addr, value);
1456 } else {
1457 ufoPush(value);
1458 ufoPush(0);
1459 ufoPush(addr);
1460 UFCALL(PAR_HANDLE_STORE_BYTE);
1465 //==========================================================================
1467 // ufoImgEmitAlign
1469 //==========================================================================
1470 UFO_FORCE_INLINE void ufoImgEmitAlign (void) {
1471 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1475 //==========================================================================
1477 // ufoResetTib
1479 //==========================================================================
1480 UFO_FORCE_INLINE void ufoResetTib (void) {
1481 uint32_t defTIB = ufoImgGetU32(ufoAddrDefTIB);
1482 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1483 if (defTIB == 0) {
1484 // create new TIB handle
1485 UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
1486 defTIB = tibh->ufoHandle;
1487 ufoImgPutU32(ufoAddrDefTIB, defTIB);
1489 if ((defTIB & UFO_ADDR_HANDLE_BIT) != 0) {
1490 UfoHandle *hh = ufoGetHandle(defTIB);
1491 if (hh == NULL) ufoFatal("default TIB is not allocated");
1492 if (hh->size == 0) {
1493 ufo_assert(hh->data == NULL);
1494 hh->data = calloc(1, UFO_ADDR_HANDLE_OFS_MASK + 1);
1495 if (hh->data == NULL) ufoFatal("out of memory for default TIB");
1496 hh->size = UFO_ADDR_HANDLE_OFS_MASK + 1;
1499 const uint32_t oldA = ufoRegA;
1500 ufoImgPutU32(ufoAddrTIBx, defTIB);
1501 ufoImgPutU32(ufoAddrINx, 0);
1502 ufoRegA = defTIB;
1503 ufoPush(0); // value
1504 ufoPush(0); // offset
1505 UFCALL(CPOKE_REGA_IDX);
1506 ufoRegA = oldA;
1510 //==========================================================================
1512 // ufoTibEnsureSize
1514 //==========================================================================
1515 UFO_DISABLE_INLINE void ufoTibEnsureSize (uint32_t size) {
1516 if (size > 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1517 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1518 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1519 if ((tib & UFO_ADDR_HANDLE_BIT) != 0) {
1520 UfoHandle *hh = ufoGetHandle(tib);
1521 if (hh == NULL) {
1522 ufoFatal("cannot resize TIB, TIB is not a handle");
1524 if (hh->size < size) {
1525 const uint32_t newsz = (size | 0xfffU) + 1u;
1526 uint8_t *nx = realloc(hh->data, newsz);
1527 if (nx == NULL) ufoFatal("out of memory for restored TIB");
1528 hh->data = nx;
1529 hh->size = newsz;
1532 #if 0
1533 else {
1534 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib);
1536 #endif
1540 //==========================================================================
1542 // ufoTibGetSize
1544 //==========================================================================
1546 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1547 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1548 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1549 ufoFatal("cannot query TIB, TIB is not a handle");
1551 UfoHandle *hh = ufoGetHandle(tib);
1552 if (hh == NULL) {
1553 ufoFatal("cannot query TIB, TIB is not a handle");
1555 return hh->size;
1560 //==========================================================================
1562 // ufoTibPeekCh
1564 //==========================================================================
1565 UFO_FORCE_INLINE uint8_t ufoTibPeekCh (void) {
1566 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx));
1570 //==========================================================================
1572 // ufoTibPeekChOfs
1574 //==========================================================================
1575 UFO_FORCE_INLINE uint8_t ufoTibPeekChOfs (uint32_t ofs) {
1576 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1577 if (ofs <= UFO_ADDR_HANDLE_OFS_MASK || (tib & UFO_ADDR_HANDLE_BIT) == 0) {
1578 return (uint8_t)ufoImgGetU8Ext(tib + ufoImgGetU32(ufoAddrINx) + ofs);
1579 } else {
1580 return 0;
1585 //==========================================================================
1587 // ufoTibPokeChOfs
1589 //==========================================================================
1590 UFO_DISABLE_INLINE void ufoTibPokeChOfs (uint8_t ch, uint32_t ofs) {
1591 const uint32_t oldA = ufoRegA;
1592 ufoRegA = ufoImgGetU32(ufoAddrTIBx);
1593 ufoPush(ch);
1594 ufoPush(ufoImgGetU32(ufoAddrINx) + ofs);
1595 UFCALL(CPOKE_REGA_IDX);
1596 ufoRegA = oldA;
1600 //==========================================================================
1602 // ufoTibGetCh
1604 //==========================================================================
1605 UFO_FORCE_INLINE uint8_t ufoTibGetCh (void) {
1606 const uint8_t ch = ufoTibPeekCh();
1607 if (ch) ufoImgPutU32(ufoAddrINx, ufoImgGetU32(ufoAddrINx) + 1u);
1608 return ch;
1612 //==========================================================================
1614 // ufoTibSkipCh
1616 //==========================================================================
1617 UFO_FORCE_INLINE void ufoTibSkipCh (void) {
1618 (void)ufoTibGetCh();
1622 // ////////////////////////////////////////////////////////////////////////// //
1623 // native CFA implementations
1626 //==========================================================================
1628 // ufoDoForth
1630 //==========================================================================
1631 static void ufoDoForth (uint32_t pfa) {
1632 ufoRPush(ufoIP);
1633 ufoIP = pfa;
1637 //==========================================================================
1639 // ufoDoVariable
1641 //==========================================================================
1642 static void ufoDoVariable (uint32_t pfa) {
1643 ufoPush(pfa);
1647 //==========================================================================
1649 // ufoDoUserVariable
1651 //==========================================================================
1652 static void ufoDoUserVariable (uint32_t pfa) {
1653 ufoPush(ufoImgGetU32(pfa));
1657 //==========================================================================
1659 // ufoDoValue
1661 //==========================================================================
1662 static void ufoDoValue (uint32_t pfa) {
1663 ufoPush(ufoImgGetU32(pfa));
1667 //==========================================================================
1669 // ufoDoConst
1671 //==========================================================================
1672 static void ufoDoConst (uint32_t pfa) {
1673 ufoPush(ufoImgGetU32(pfa));
1677 //==========================================================================
1679 // ufoDoDefer
1681 //==========================================================================
1682 static void ufoDoDefer (uint32_t pfa) {
1683 const uint32_t cfa = ufoImgGetU32(pfa);
1684 if (cfa != 0) {
1685 ufoRPush(cfa);
1686 ufoVMRPopCFA = 1;
1691 //==========================================================================
1693 // ufoDoVoc
1695 //==========================================================================
1696 static void ufoDoVoc (uint32_t pfa) {
1697 ufoImgPutU32(ufoAddrContext, ufoImgGetU32(pfa));
1701 //==========================================================================
1703 // ufoDoCreate
1705 //==========================================================================
1706 static void ufoDoCreate (uint32_t pfa) {
1707 ufoPush(pfa);
1711 //==========================================================================
1713 // ufoPushInFile
1715 // this also increments last used file id
1717 //==========================================================================
1718 static void ufoPushInFile (void) {
1719 if (ufoFileStackPos >= UFO_MAX_NESTED_INCLUDES) ufoFatal("too many includes");
1720 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
1721 stk->fl = ufoInFile;
1722 stk->fname = ufoInFileName;
1723 stk->fline = ufoInFileLine;
1724 stk->id = ufoFileId;
1725 stk->incpath = (ufoLastIncPath ? strdup(ufoLastIncPath) : NULL);
1726 stk->sysincpath = (ufoLastSysIncPath ? strdup(ufoLastSysIncPath) : NULL);
1727 ufoFileStackPos += 1;
1728 ufoInFile = NULL;
1729 ufoInFileName = NULL;
1730 ufoInFileLine = 0;
1731 ufoLastUsedFileId += 1;
1732 ufo_assert(ufoLastUsedFileId != 0); // just in case ;-)
1733 //ufoLastIncPath = NULL;
1737 //==========================================================================
1739 // ufoWipeIncludeStack
1741 //==========================================================================
1742 static void ufoWipeIncludeStack (void) {
1743 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
1744 if (ufoInFile) { fclose(ufoInFile); ufoInFile = NULL; }
1745 if (ufoLastIncPath) { free(ufoLastIncPath); ufoLastIncPath = NULL; }
1746 if (ufoLastSysIncPath) { free(ufoLastSysIncPath); ufoLastSysIncPath = NULL; }
1747 while (ufoFileStackPos != 0) {
1748 ufoFileStackPos -= 1;
1749 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
1750 if (stk->fl) fclose(stk->fl);
1751 if (stk->fname) free(stk->fname);
1752 if (stk->incpath) free(stk->incpath);
1757 //==========================================================================
1759 // ufoPopInFile
1761 //==========================================================================
1762 static void ufoPopInFile (void) {
1763 if (ufoFileStackPos == 0) ufoFatal("trying to pop include from empty stack");
1764 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
1765 if (ufoInFile) { fclose(ufoInFile); ufoInFile = NULL; }
1766 if (ufoLastIncPath) { free(ufoLastIncPath); ufoLastIncPath = NULL; }
1767 if (ufoLastSysIncPath) { free(ufoLastSysIncPath); ufoLastSysIncPath = NULL; }
1768 ufoFileStackPos -= 1;
1769 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
1770 ufoInFile = stk->fl;
1771 ufoInFileName = stk->fname;
1772 ufoInFileLine = stk->fline;
1773 ufoLastIncPath = stk->incpath;
1774 ufoLastSysIncPath = stk->sysincpath;
1775 ufoFileId = stk->id;
1776 ufoResetTib();
1777 #ifdef UFO_DEBUG_INCLUDE
1778 if (ufoInFileName == NULL) {
1779 fprintf(stderr, "INC-POP: no more files.\n");
1780 } else {
1781 fprintf(stderr, "INC-POP: fname: %s\n", ufoInFileName);
1783 #endif
1787 //==========================================================================
1789 // ufoDeinit
1791 //==========================================================================
1792 void ufoDeinit (void) {
1793 #ifdef UFO_DEBUG_DEBUG
1794 fprintf(stderr, "UFO: debug image used: %u; size: %u\n",
1795 ufoDebugImageUsed, ufoDebugImageSize);
1796 ufoDumpDebugImage();
1797 #endif
1799 // free all states
1800 ufoCurrState = NULL;
1801 ufoYieldedState = NULL;
1802 ufoDebuggerState = NULL;
1803 for (uint32_t fidx = 0; fidx < (uint32_t)(UFO_MAX_STATES/32); fidx += 1u) {
1804 uint32_t bmp = ufoStateUsedBitmap[fidx];
1805 if (bmp != 0) {
1806 uint32_t stid = fidx * 32u;
1807 while (bmp != 0) {
1808 if ((bmp & 0x01) != 0) ufoFreeState(ufoStateMap[stid]);
1809 stid += 1u; bmp >>= 1;
1814 free(ufoDebugImage);
1815 ufoDebugImage = NULL;
1816 ufoDebugImageUsed = 0;
1817 ufoDebugImageSize = 0;
1818 ufoDebugFileId = 0;
1819 ufoDebugLastFRecAddr = 0;
1820 ufoDebugCurrDP = 0;
1822 ufoInBacktrace = 0;
1823 ufoClearCondDefines();
1824 ufoWipeIncludeStack();
1826 // release all includes
1827 ufoInFile = NULL;
1828 if (ufoInFileName) free(ufoInFileName);
1829 if (ufoLastIncPath) free(ufoLastIncPath);
1830 if (ufoLastSysIncPath) free(ufoLastSysIncPath);
1831 ufoInFileName = NULL; ufoLastIncPath = NULL; ufoLastSysIncPath = NULL;
1832 ufoInFileLine = 0;
1834 free(ufoForthCFAs);
1835 ufoForthCFAs = NULL;
1836 ufoCFAsUsed = 0;
1838 free(ufoImage);
1839 ufoImage = NULL;
1840 ufoImageSize = 0;
1842 ufoMode = UFO_MODE_NATIVE;
1843 ufoVSP = 0;
1844 ufoForthVocId = 0; ufoCompilerVocId = 0;
1845 ufoSingleStep = 0;
1847 // free all handles
1848 for (uint32_t f = 0; f < ufoHandlesUsed; f += 1) {
1849 UfoHandle *hh = ufoHandles[f];
1850 if (hh != NULL) {
1851 if (hh->data != NULL) free(hh->data);
1852 free(hh);
1855 if (ufoHandles != NULL) free(ufoHandles);
1856 ufoHandles = NULL; ufoHandlesUsed = 0; ufoHandlesAlloted = 0;
1857 ufoHandleFreeList = NULL;
1859 ufoLastEmitWasCR = 1;
1861 ufoClearCondDefines();
1865 //==========================================================================
1867 // ufoDumpWordHeader
1869 //==========================================================================
1870 __attribute__((unused)) static void ufoDumpWordHeader (const uint32_t lfa) {
1871 fprintf(stderr, "=== WORD: LFA: 0x%08x ===\n", lfa);
1872 if (lfa != 0) {
1873 fprintf(stderr, " (DFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_DFA(lfa)));
1874 fprintf(stderr, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa)));
1875 fprintf(stderr, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa)));
1876 fprintf(stderr, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa)));
1877 fprintf(stderr, " (LFA): 0x%08x\n", ufoImgGetU32(lfa));
1878 fprintf(stderr, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)));
1879 const uint32_t cfa = UFO_LFA_TO_CFA(lfa);
1880 fprintf(stderr, " CFA: 0x%08x\n", cfa);
1881 fprintf(stderr, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa));
1882 fprintf(stderr, " (CFA): 0x%08x\n", ufoImgGetU32(cfa));
1883 const uint32_t nfa = UFO_LFA_TO_NFA(lfa);
1884 const uint32_t nlen = ufoImgGetU8(nfa);
1885 fprintf(stderr, " NFA: 0x%08x (nlen: %u)\n", nfa, nlen);
1886 const uint32_t flags = ufoImgGetU32(nfa);
1887 fprintf(stderr, " FLAGS: 0x%08x\n", flags);
1888 if ((flags & 0xffff0000U) != 0) {
1889 fprintf(stderr, " FLAGS:");
1890 if (flags & UFW_FLAG_IMMEDIATE) fprintf(stderr, " IMM");
1891 if (flags & UFW_FLAG_SMUDGE) fprintf(stderr, " SMUDGE");
1892 if (flags & UFW_FLAG_NORETURN) fprintf(stderr, " NORET");
1893 if (flags & UFW_FLAG_HIDDEN) fprintf(stderr, " HIDDEN");
1894 if (flags & UFW_FLAG_CBLOCK) fprintf(stderr, " CBLOCK");
1895 if (flags & UFW_FLAG_VOCAB) fprintf(stderr, " VOCAB");
1896 if (flags & UFW_FLAG_SCOLON) fprintf(stderr, " SCOLON");
1897 if (flags & UFW_FLAG_PROTECTED) fprintf(stderr, " PROTECTED");
1898 fputc('\n', stderr);
1900 if ((flags & 0xff00U) != 0) {
1901 fprintf(stderr, " ARGS: ");
1902 switch (flags & UFW_WARG_MASK) {
1903 case UFW_WARG_NONE: fprintf(stderr, "NONE"); break;
1904 case UFW_WARG_BRANCH: fprintf(stderr, "BRANCH"); break;
1905 case UFW_WARG_LIT: fprintf(stderr, "LIT"); break;
1906 case UFW_WARG_C4STRZ: fprintf(stderr, "C4STRZ"); break;
1907 case UFW_WARG_CFA: fprintf(stderr, "CFA"); break;
1908 case UFW_WARG_CBLOCK: fprintf(stderr, "CBLOCK"); break;
1909 case UFW_WARG_VOCID: fprintf(stderr, "VOCID"); break;
1910 case UFW_WARG_C1STRZ: fprintf(stderr, "C1STRZ"); break;
1911 default: fprintf(stderr, "wtf?!"); break;
1913 fputc('\n', stderr);
1915 fprintf(stderr, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa - 1u), UFO_CFA_TO_NFA(cfa));
1916 fprintf(stderr, " NAME(%u): ", nlen);
1917 for (uint32_t f = 0; f < nlen; f += 1) {
1918 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
1919 if (ch <= 32 || ch >= 127) {
1920 fprintf(stderr, "\\x%02x", ch);
1921 } else {
1922 fprintf(stderr, "%c", (char)ch);
1925 fprintf(stderr, "\n");
1926 ufo_assert(UFO_CFA_TO_LFA(cfa) == lfa);
1931 //==========================================================================
1933 // ufoVocCheckName
1935 // return 0 or CFA
1937 //==========================================================================
1938 static uint32_t ufoVocCheckName (uint32_t lfa, const void *wname, uint32_t wnlen, uint32_t hash,
1939 int allowvochid)
1941 uint32_t res = 0;
1942 #ifdef UFO_DEBUG_FIND_WORD
1943 fprintf(stderr, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
1944 (unsigned) wnlen, (const char *)wname,
1945 lfa, (lfa != 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)) : 0), hash);
1946 ufoDumpWordHeader(lfa);
1947 #endif
1948 if (lfa != 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)) == hash) {
1949 const uint32_t lenflags = ufoImgGetU32(UFO_LFA_TO_NFA(lfa));
1950 if ((lenflags & UFW_FLAG_SMUDGE) == 0 &&
1951 (allowvochid || (lenflags & UFW_FLAG_HIDDEN) == 0))
1953 const uint32_t nlen = lenflags&0xffU;
1954 if (nlen == wnlen) {
1955 uint32_t naddr = UFO_LFA_TO_NFA(lfa) + 4u;
1956 uint32_t pos = 0;
1957 while (pos < nlen) {
1958 uint8_t c0 = ((const unsigned char *)wname)[pos];
1959 if (c0 >= 'a' && c0 <= 'z') c0 = c0 - 'a' + 'A';
1960 uint8_t c1 = ufoImgGetU8(naddr + pos);
1961 if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A';
1962 if (c0 != c1) break;
1963 pos += 1u;
1965 if (pos == nlen) {
1966 // i found her!
1967 naddr += pos + 1u;
1968 res = UFO_ALIGN4(naddr);
1973 return res;
1977 //==========================================================================
1979 // ufoFindWordInVoc
1981 // return 0 or CFA
1983 //==========================================================================
1984 static uint32_t ufoFindWordInVoc (const void *wname, uint32_t wnlen, uint32_t hash,
1985 uint32_t vocid, int allowvochid)
1987 uint32_t res = 0;
1988 if (wname == NULL) ufo_assert(wnlen == 0);
1989 if (wnlen != 0 && vocid != 0) {
1990 if (hash == 0) hash = joaatHashBufCI(wname, wnlen);
1991 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1992 fprintf(stderr, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
1993 (unsigned) wnlen, (const char *)wname,
1994 vocid, hash, ufoImgGetU32(vocid + UFW_VOCAB_OFS_HTABLE));
1995 #endif
1996 const uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
1997 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
1998 // hash table present, use it
1999 uint32_t bfa = htbl + (hash % (uint32_t)UFO_HASHTABLE_SIZE) * 4u;
2000 bfa = ufoImgGetU32(bfa);
2001 while (res == 0 && bfa != 0) {
2002 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2003 fprintf(stderr, "IN-VOC: bfa: 0x%08x\n", bfa);
2004 #endif
2005 res = ufoVocCheckName(UFO_BFA_TO_LFA(bfa), wname, wnlen, hash, allowvochid);
2006 bfa = ufoImgGetU32(bfa);
2008 } else {
2009 // no hash table, use linear search
2010 uint32_t lfa = vocid + UFW_VOCAB_OFS_LATEST;
2011 lfa = ufoImgGetU32(lfa);
2012 while (res == 0 && lfa != 0) {
2013 res = ufoVocCheckName(lfa, wname, wnlen, hash, allowvochid);
2014 lfa = ufoImgGetU32(lfa);
2018 return res;
2022 //==========================================================================
2024 // ufoFindColon
2026 // return part after the colon, or `NULL`
2028 //==========================================================================
2029 static const void *ufoFindColon (const void *wname, uint32_t wnlen) {
2030 const void *res = NULL;
2031 if (wnlen != 0) {
2032 ufo_assert(wname != NULL);
2033 const char *str = (const char *)wname;
2034 while (wnlen != 0 && str[0] != ':') {
2035 str += 1; wnlen -= 1;
2037 if (wnlen != 0) {
2038 res = (const void *)(str + 1); // skip colon
2041 return res;
2045 //==========================================================================
2047 // ufoFindWordInVocAndParents
2049 //==========================================================================
2050 static uint32_t ufoFindWordInVocAndParents (const void *wname, uint32_t wnlen, uint32_t hash,
2051 uint32_t vocid, int allowvochid)
2053 uint32_t res = 0;
2054 if (hash == 0) hash = joaatHashBufCI(wname, wnlen);
2055 while (res == 0 && vocid != 0) {
2056 res = ufoFindWordInVoc(wname, wnlen, hash, vocid, allowvochid);
2057 vocid = ufoImgGetU32(vocid + UFW_VOCAB_OFS_PARENT);
2059 return res;
2063 //==========================================================================
2065 // ufoFindWordNameRes
2067 // find with name resolution
2069 // return 0 or CFA
2071 //==========================================================================
2072 static uint32_t ufoFindWordNameRes (const void *wname, uint32_t wnlen) {
2073 uint32_t res = 0;
2074 if (wnlen != 0 && *(const char *)wname != ':') {
2075 ufo_assert(wname != NULL);
2077 const void *stx = wname;
2078 wname = ufoFindColon(wname, wnlen);
2079 if (wname != NULL) {
2080 // look in all vocabs (excluding hidden ones)
2081 uint32_t xlen = (uint32_t)(ptrdiff_t)(wname - stx) - 1u;
2082 ufo_assert(xlen > 0 && xlen < 255);
2083 uint32_t xhash = joaatHashBufCI(stx, xlen);
2084 uint32_t voclink = ufoImgGetU32(ufoAddrVocLink);
2085 #ifdef UFO_DEBUG_FIND_WORD_COLON
2086 fprintf(stderr, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2087 (unsigned)xlen, (const char *)stx, xhash, voclink);
2088 #endif
2089 while (res == 0 && voclink != 0) {
2090 const uint32_t vhdraddr = voclink - UFW_VOCAB_OFS_VOCLINK + UFW_VOCAB_OFS_HEADER;
2091 const uint32_t vhdr = ufoImgGetU32(vhdraddr);
2092 if (vhdr != 0) {
2093 res = ufoVocCheckName(UFO_NFA_TO_LFA(vhdr), stx, xlen, xhash, 0);
2095 if (res == 0) voclink = ufoImgGetU32(voclink);
2097 if (res != 0) {
2098 uint32_t vocid = voclink - UFW_VOCAB_OFS_VOCLINK;
2099 ufo_assert(voclink != 0);
2100 wnlen -= xlen + 1;
2101 #ifdef UFO_DEBUG_FIND_WORD_COLON
2102 fprintf(stderr, "searching {%.*s}(%u) in {%.*s}\n",
2103 (unsigned)wnlen, wname, wnlen, (unsigned)xlen, stx);
2104 #endif
2105 while (res != 0 && wname != NULL) {
2106 stx = wname;
2107 wname = ufoFindColon(wname, wnlen);
2108 if (wname == NULL) xlen = wnlen; else xlen = (uint32_t)(ptrdiff_t)(wname - stx) - 1u;
2109 ufo_assert(xlen > 0 && xlen < 255);
2110 res = ufoFindWordInVocAndParents(stx, xlen, 0, vocid, 1);
2111 if (res != 0) {
2112 wnlen -= xlen + 1;
2113 if (wname != NULL) {
2114 // it should be a vocabulary
2115 const uint32_t nfa = UFO_CFA_TO_NFA(res);
2116 if ((ufoImgGetU32(nfa) & UFW_FLAG_VOCAB) != 0) {
2117 vocid = ufoImgGetU32(UFO_CFA_TO_PFA(res)); // pfa points to vocabulary
2118 } else {
2119 res = 0;
2128 return res;
2132 //==========================================================================
2134 // ufoFindWord
2136 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2138 // return 0 or CFA
2140 //==========================================================================
2141 static uint32_t ufoFindWord (const char *wname) {
2142 uint32_t res = 0;
2143 if (wname && wname[0] != 0) {
2144 const size_t wnlen = strlen(wname);
2145 ufo_assert(wnlen < 8192);
2146 uint32_t ctx = ufoImgGetU32(ufoAddrContext);
2147 const uint32_t hash = joaatHashBufCI(wname, (uint32_t)wnlen);
2149 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2151 // first search in context
2152 res = ufoFindWordInVocAndParents(wname, (uint32_t)wnlen, hash, ctx, (ctx == ufoImgGetU32(ufoAddrCurrent)));
2154 // now try vocabulary stack
2155 uint32_t vstp = ufoVSP;
2156 while (res == 0 && vstp != 0) {
2157 vstp -= 1;
2158 ctx = ufoVocStack[vstp];
2159 res = ufoFindWordInVocAndParents(wname, (uint32_t)wnlen, hash, ctx, (ctx == ufoImgGetU32(ufoAddrCurrent)));
2162 // if not found, try name resolution
2163 if (res == 0) res = ufoFindWordNameRes(wname, (uint32_t)wnlen);
2166 return res;
2170 //==========================================================================
2172 // ufoCreateWordHeader
2174 // create word header up to CFA, link to the current dictionary
2176 //==========================================================================
2177 static void ufoCreateWordHeader (const char *wname, uint32_t flags) {
2178 if (wname == NULL) wname = "";
2179 const size_t wnlen = strlen(wname);
2180 ufo_assert(wnlen < UFO_MAX_WORD_LENGTH);
2181 const uint32_t hash = joaatHashBufCI(wname, (uint32_t)wnlen);
2182 const uint32_t curr = ufoImgGetU32(ufoAddrCurrent);
2183 ufo_assert(curr != 0);
2184 // redefine check
2185 if (wnlen != 0 && ufoImgGetU32(ufoAddrRedefineWarning) != UFO_REDEF_WARN_DONT_CARE) {
2186 const uint32_t cfa = ufoFindWordInVoc(wname, wnlen, hash, curr, 1);
2187 if (cfa) {
2188 const uint32_t nfa = UFO_CFA_TO_NFA(cfa);
2189 const uint32_t flags = ufoImgGetU32(nfa);
2190 if ((flags & UFW_FLAG_PROTECTED) != 0) {
2191 ufoFatal("trying to redefine protected word '%s'", wname);
2192 } else if (ufoImgGetU32(ufoAddrRedefineWarning) != UFO_REDEF_WARN_NONE) {
2193 ufoWarning("redefining word '%s'", wname);
2197 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2198 const uint32_t bkt = (hash % (uint32_t)UFO_HASHTABLE_SIZE) * 4u;
2199 const uint32_t htbl = curr + UFW_VOCAB_OFS_HTABLE;
2200 ufoImgEmitAlign();
2201 ufoImgEmitU32(0); // dfa
2202 const uint32_t xfaAddr = UFO_GET_DP();
2203 if ((xfaAddr & UFO_ADDR_TEMP_BIT) == 0) {
2204 // link previous yfa here
2205 const uint32_t lastxfa = ufoImgGetU32(ufoAddrLastXFA);
2206 // fix YFA of the previous word
2207 if (lastxfa != 0) {
2208 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa), UFO_XFA_TO_YFA(xfaAddr));
2210 // our XFA points to the previous XFA
2211 ufoImgEmitU32(lastxfa); // xfa
2212 // update last XFA
2213 ufoImgPutU32(ufoAddrLastXFA, xfaAddr);
2214 } else {
2215 ufoImgEmitU32(0); // xfa
2217 ufoImgEmitU32(0); // yfa
2218 // bucket link (bfa)
2219 if (wnlen == 0 || ufoImgGetU32(htbl) == UFO_NO_HTABLE_FLAG) {
2220 ufoImgEmitU32(0);
2221 } else {
2222 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2223 fprintf(stderr, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2224 wname, curr, htbl, bkt);
2225 fprintf(stderr, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl + bkt), UFO_GET_DP());
2226 #endif
2227 // bfa points to bfa
2228 const uint32_t bfa = UFO_GET_DP();
2229 ufoImgEmitU32(ufoImgGetU32(htbl + bkt));
2230 ufoImgPutU32(htbl + bkt, bfa);
2232 // lfa
2233 const uint32_t lfa = UFO_GET_DP();
2234 ufoImgEmitU32(ufoImgGetU32(curr + UFW_VOCAB_OFS_LATEST));
2235 // fix voc latest
2236 ufoImgPutU32(curr + UFW_VOCAB_OFS_LATEST, lfa);
2237 // name hash
2238 ufoImgEmitU32(hash);
2239 // name length
2240 const uint32_t nfa = UFO_GET_DP();
2241 ufoImgEmitU32(((uint32_t)wnlen&0xffU) | (flags & 0xffffff00U));
2242 const uint32_t nstart = UFO_GET_DP();
2243 // put name
2244 for (size_t f = 0; f < wnlen; f += 1) {
2245 ufoImgEmitU8(((const unsigned char *)wname)[f]);
2247 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2248 const uint32_t nend = UFO_GET_DP(); // length byte itself is not included
2249 // name length, again
2250 ufo_assert(nend - nstart <= 255);
2251 ufoImgEmitU8((uint8_t)(nend - nstart));
2252 ufo_assert((UFO_GET_DP() & 3) == 0);
2253 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa);
2254 if ((nend & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(nend);
2255 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2256 fprintf(stderr, "*** NEW HEADER ***\n");
2257 fprintf(stderr, "CFA: 0x%08x\n", UFO_GET_DP());
2258 fprintf(stderr, "NSTART: 0x%08x\n", nstart);
2259 fprintf(stderr, "NEND: 0x%08x\n", nend);
2260 fprintf(stderr, "NLEN: %u (%u)\n", nend - nstart, ufoImgGetU8(UFO_GET_DP() - 1u));
2261 ufoDumpWordHeader(lfa);
2262 #endif
2263 #if 0
2264 fprintf(stderr, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname);
2265 #endif
2269 //==========================================================================
2271 // ufoDecompilePart
2273 //==========================================================================
2274 static void ufoDecompilePart (uint32_t addr, uint32_t eaddr, int indent) {
2275 uint32_t count;
2276 FILE *fo = stdout;
2277 while (addr < eaddr) {
2278 uint32_t cfa = ufoImgGetU32(addr);
2279 for (int n = 0; n < indent; n += 1) fputc(' ', fo);
2280 fprintf(fo, "%6u: 0x%08x: ", addr, cfa);
2281 uint32_t nfa = UFO_CFA_TO_NFA(cfa);
2282 uint32_t flags = ufoImgGetU32(nfa);
2283 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2284 uint32_t nlen = flags & 0xffU;
2285 for (uint32_t f = 0; f < nlen; f += 1) {
2286 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
2287 if (ch <= 32 || ch >= 127) {
2288 fprintf(fo, "\\x%02x", ch);
2289 } else {
2290 fprintf(fo, "%c", (char)ch);
2293 addr += 4u;
2294 switch (flags & UFW_WARG_MASK) {
2295 case UFW_WARG_NONE:
2296 break;
2297 case UFW_WARG_BRANCH:
2298 fprintf(fo, " @%u", ufoImgGetU32(addr)); addr += 4u;
2299 break;
2300 case UFW_WARG_LIT:
2301 fprintf(fo, " %u : %d : 0x%08x", ufoImgGetU32(addr),
2302 (int32_t)ufoImgGetU32(addr), ufoImgGetU32(addr)); addr += 4u;
2303 break;
2304 case UFW_WARG_C4STRZ:
2305 count = ufoImgGetU32(addr); addr += 4;
2306 print_str:
2307 fprintf(fo, " str:");
2308 for (int f = 0; f < count; f += 1) {
2309 const uint8_t ch = ufoImgGetU8(addr); addr += 1u;
2310 if (ch <= 32 || ch >= 127) {
2311 fprintf(fo, "\\x%02x", ch);
2312 } else {
2313 fprintf(fo, "%c", (char)ch);
2316 addr += 1u; // skip zero byte
2317 addr = UFO_ALIGN4(addr);
2318 break;
2319 case UFW_WARG_CFA:
2320 cfa = ufoImgGetU32(addr); addr += 4u;
2321 fprintf(fo, " CFA:%u: ", cfa);
2322 nfa = UFO_CFA_TO_NFA(cfa);
2323 nlen = ufoImgGetU8(nfa);
2324 for (uint32_t f = 0; f < nlen; f += 1) {
2325 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
2326 if (ch <= 32 || ch >= 127) {
2327 fprintf(fo, "\\x%02x", ch);
2328 } else {
2329 fprintf(fo, "%c", (char)ch);
2332 break;
2333 case UFW_WARG_CBLOCK:
2334 fprintf(fo, " CBLOCK:%u", ufoImgGetU32(addr)); addr += 4u;
2335 break;
2336 case UFW_WARG_VOCID:
2337 fprintf(fo, " VOCID:%u", ufoImgGetU32(addr)); addr += 4u;
2338 break;
2339 case UFW_WARG_C1STRZ:
2340 count = ufoImgGetU8(addr); addr += 1;
2341 goto print_str;
2343 case UFW_WARG_U8:
2344 fprintf(fo, " ubyte:%u", ufoImgGetU8(addr)); addr += 1u;
2345 break;
2346 case UFW_WARG_S8:
2347 fprintf(fo, " sbyte:%u", ufoImgGetU8(addr)); addr += 1u;
2348 break;
2349 case UFW_WARG_U16:
2350 fprintf(fo, " uword:%u", ufoImgGetU16(addr)); addr += 2u;
2351 break;
2352 case UFW_WARG_S16:
2353 fprintf(fo, " sword:%u", ufoImgGetU16(addr)); addr += 2u;
2354 break;
2356 default:
2357 fprintf(fo, " -- WTF?!\n");
2358 abort();
2360 fputc('\n', fo);
2365 //==========================================================================
2367 // ufoDecompileWord
2369 //==========================================================================
2370 static void ufoDecompileWord (const uint32_t cfa) {
2371 if (cfa != 0) {
2372 const uint32_t lfa = UFO_CFA_TO_LFA(cfa);
2373 fprintf(stdout, "#### DECOMPILING CFA %u ###\n", cfa);
2374 ufoDumpWordHeader(lfa);
2375 const uint32_t yfa = ufoGetWordEndAddr(cfa);
2376 if (ufoImgGetU32(cfa) == ufoDoForthCFA) {
2377 fprintf(stdout, "--- DECOMPILED CODE ---\n");
2378 ufoDecompilePart(UFO_CFA_TO_PFA(cfa), yfa, 0);
2379 fprintf(stdout, "=======================\n");
2385 //==========================================================================
2387 // ufoBTShowWordName
2389 //==========================================================================
2390 static void ufoBTShowWordName (uint32_t nfa) {
2391 if (nfa != 0) {
2392 uint32_t len = ufoImgGetU8(nfa); nfa += 4u;
2393 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2394 while (len != 0) {
2395 uint8_t ch = ufoImgGetU8(nfa); nfa += 1u; len -= 1u;
2396 if (ch <= 32 || ch >= 127) {
2397 fprintf(stderr, "\\x%02x", ch);
2398 } else {
2399 fprintf(stderr, "%c", (char)ch);
2406 //==========================================================================
2408 // ufoBacktrace
2410 //==========================================================================
2411 static void ufoBacktrace (uint32_t ip) {
2412 // dump data stack (top 16)
2413 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2414 fflush(NULL);
2416 fprintf(stderr, "***UFO STACK DEPTH: %u\n", ufoSP);
2417 uint32_t xsp = ufoSP;
2418 if (xsp > 16) xsp = 16;
2419 for (uint32_t sp = 0; sp < xsp; ++sp) {
2420 fprintf(stderr, " %2u: 0x%08x %d\n", sp,
2421 ufoDStack[xsp - sp - 1], (int32_t)ufoDStack[xsp - sp - 1]);
2423 if (ufoSP > 16) fprintf(stderr, " ...more...\n");
2425 // dump return stack (top 32)
2426 uint32_t nfa;
2427 uint32_t fline;
2428 const char *fname;
2430 fprintf(stderr, "***UFO RETURN STACK DEPTH: %u\n", ufoRP);
2431 if (ip != 0) {
2432 nfa = ufoFindWordForIP(ip);
2433 if (nfa != 0) {
2434 fprintf(stderr, " **: %8u -- ", ip);
2435 ufoBTShowWordName(nfa);
2436 fname = ufoFindFileForIP(ip, &fline);
2437 if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }
2438 fputc('\n', stderr);
2441 uint32_t rp = ufoRP;
2442 uint32_t rscount = 0;
2443 if (rp > UFO_RSTACK_SIZE) rp = UFO_RSTACK_SIZE;
2444 while (rscount != 32 && rp != 0) {
2445 rp -= 1;
2446 const uint32_t val = ufoRStack[rp];
2447 nfa = ufoFindWordForIP(val);
2448 if (nfa != 0) {
2449 fprintf(stderr, " %2u: %8u -- ", ufoRP - rp - 1u, val);
2450 ufoBTShowWordName(nfa);
2451 fname = ufoFindFileForIP(val - 4u, &fline);
2452 if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }
2453 fputc('\n', stderr);
2454 } else {
2455 fprintf(stderr, " %2u: 0x%08x %d\n", ufoRP - rp - 1u, val, (int32_t)val);
2457 rscount += 1;
2459 if (ufoRP > 32) fprintf(stderr, " ...more...\n");
2461 fflush(NULL);
2465 //==========================================================================
2467 // ufoDumpVocab
2469 //==========================================================================
2471 static void ufoDumpVocab (uint32_t vocid) {
2472 if (vocid != 0) {
2473 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2474 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2475 vochdr = ufoImgGetU32(vochdr);
2476 if (vochdr != 0) {
2477 fprintf(stderr, "--- HEADER ---\n");
2478 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2479 fprintf(stderr, "========\n");
2480 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2481 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2482 fprintf(stderr, "--- HASH TABLE ---\n");
2483 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2484 uint32_t bfa = ufoImgGetU32(htbl);
2485 if (bfa != 0) {
2486 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2487 do {
2488 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2489 bfa = ufoImgGetU32(bfa);
2490 } while (bfa != 0);
2492 htbl += 4u;
2501 // if set, this will be used when we are out of include files. intended for UrAsm.
2502 // return 0 if there is no more lines, otherwise the string should be copied
2503 // to buffer, `*fname` and `*fline` should be properly set.
2504 int (*ufoFileReadLine) (void *buf, size_t bufsize, const char **fname, int *fline) = NULL;
2507 //==========================================================================
2509 // ufoLoadNextUserLine
2511 //==========================================================================
2512 static int ufoLoadNextUserLine (void) {
2513 uint32_t tibPos = 0;
2514 const char *fname = NULL;
2515 int fline = 0;
2516 ufoResetTib();
2517 if (ufoFileReadLine != NULL && ufoFileReadLine(ufoCurrFileLine, 510, &fname, &fline) != 0) {
2518 ufoCurrFileLine[510] = 0;
2519 uint32_t slen = (uint32_t)strlen(ufoCurrFileLine);
2520 while (slen != 0 && (ufoCurrFileLine[slen - 1u] == 10 || ufoCurrFileLine[slen - 1u] == 13)) {
2521 slen -= 1u;
2523 if (tibPos + slen + 1u > UFO_ADDR_HANDLE_OFS_MASK) {
2524 ufoFatal("input text line too long (at least %u bytes)", tibPos + slen);
2526 ufoTibEnsureSize(tibPos + slen + 1u);
2527 for (uint32_t f = 0; f < slen; f += 1) {
2528 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine)[f], tibPos + f);
2530 ufoTibPokeChOfs(0, tibPos + slen);
2531 tibPos += slen;
2532 if (fname == NULL) fname = "<user>";
2533 if (ufoInFileName == NULL || strcmp(ufoInFileName, fname) != 0) {
2534 free(ufoInFileName);
2535 ufoInFileName = strdup(fname);
2536 if (ufoInFileName == NULL) ufoFatal("out of memory");
2538 ufoInFileLine = fline;
2539 return 1;
2540 } else {
2541 return 0;
2546 //==========================================================================
2548 // ufoLoadNextLine_NativeMode
2550 // load next file line into TIB
2551 // always strips final '\n'
2553 // return 0 on EOF, 1 on success
2555 //==========================================================================
2556 static int ufoLoadNextLine (int crossInclude) {
2557 int done = 0;
2558 uint32_t tibPos = 0;
2559 ufoResetTib();
2561 if (ufoMode == UFO_MODE_MACRO) {
2562 //fprintf(stderr, "***MAC!\n");
2563 return 0;
2566 while (ufoInFile != NULL && !done) {
2567 if (fgets(ufoCurrFileLine, 510, ufoInFile) != NULL) {
2568 // check for a newline
2569 // if there is no newline char at the end, the string was truncated
2570 ufoCurrFileLine[510] = 0;
2571 const uint32_t slen = (uint32_t)strlen(ufoCurrFileLine);
2572 if (tibPos + slen + 1u > UFO_ADDR_HANDLE_OFS_MASK) {
2573 ufoFatal("input text line too long (at least %u bytes)", tibPos + slen);
2575 ufoTibEnsureSize(tibPos + slen + 1u);
2576 for (uint32_t f = 0; f < slen; f += 1) {
2577 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine)[f], tibPos + f);
2579 ufoTibPokeChOfs(0, tibPos + slen);
2580 tibPos += slen;
2581 if (slen != 0 && (ufoCurrFileLine[slen - 1u] == 13 || ufoCurrFileLine[slen - 1u] == 10)) {
2582 ++ufoInFileLine;
2583 done = 1;
2584 } else {
2585 // continuation, nothing to do
2587 } else {
2588 // if we read nothing, this is EOF
2589 if (tibPos == 0 && crossInclude) {
2590 // we read nothing, and allowed to cross include boundaries
2591 ufoPopInFile();
2592 } else {
2593 done = 1;
2598 if (tibPos == 0) {
2599 // eof, try user-supplied input
2600 if (ufoFileStackPos == 0) {
2601 return ufoLoadNextUserLine();
2602 } else {
2603 return 0;
2605 } else {
2606 // if we read at least something, this is not EOF
2607 return 1;
2612 // ////////////////////////////////////////////////////////////////////////// //
2613 // debug
2615 // DUMP-STACK
2616 // ( -- )
2617 UFWORD(DUMP_STACK) {
2618 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2619 printf("***UFO STACK DEPTH: %u\n", ufoSP);
2620 uint32_t left = 32;
2621 uint32_t sp = ufoSP;
2622 while (sp != 0 && left != 0) {
2623 sp -= 1; left -= 1;
2624 printf(" %4u: 0x%08x %d\n", sp, ufoDStack[sp], (int32_t)ufoDStack[sp]);
2626 if (sp != 0) printf("...more...\n");
2627 ufoLastEmitWasCR = 1;
2630 // BACKTRACE
2631 UFWORD(UFO_BACKTRACE) {
2632 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2633 fflush(NULL);
2634 if (ufoInFile != NULL) {
2635 fprintf(stderr, "*** at file %s, line %d ***\n", ufoInFileName, ufoInFileLine);
2636 } else {
2637 fprintf(stderr, "*** somewhere in time ***\n");
2639 ufoBacktrace(ufoIP);
2643 // ////////////////////////////////////////////////////////////////////////// //
2644 // SP0!
2645 // ( -- )
2646 UFWORD(SP0_STORE) { ufoSP = 0; }
2648 // RP0!
2649 // ( -- )
2650 UFWORD(RP0_STORE) {
2651 if (ufoRP != ufoRPTop) {
2652 ufoRP = ufoRPTop;
2653 // we need to push a dummy value
2654 ufoRPush(0xdeadf00d);
2658 // PAD
2659 // ( -- pad )
2660 // PAD is at the beginning of temp area
2661 UFWORD(PAD) {
2662 ufoPush(UFO_PAD_ADDR);
2666 // ////////////////////////////////////////////////////////////////////////// //
2667 // peeks and pokes with address register
2670 // A>
2671 // ( -- regA )
2672 UFWORD(REGA_LOAD) {
2673 ufoPush(ufoRegA);
2676 // >A
2677 // ( regA -- )
2678 UFWORD(REGA_STORE) {
2679 ufoRegA = ufoPop();
2682 // A-SWAP
2683 // ( regA -- oldA )
2684 // swap TOS and A
2685 UFWORD(REGA_SWAP) {
2686 const uint32_t newa = ufoPop();
2687 ufoPush(ufoRegA);
2688 ufoRegA = newa;
2691 // +1>A
2692 // ( -- )
2693 UFWORD(REGA_INC) {
2694 ufoRegA += 1u;
2697 // A>R
2698 // ( -- | rega )
2699 UFWORD(REGA_TO_R) {
2700 ufoRPush(ufoRegA);
2703 // R>A
2704 // ( | rega -- )
2705 UFWORD(R_TO_REGA) {
2706 ufoRegA = ufoRPop();
2710 // ////////////////////////////////////////////////////////////////////////// //
2711 // useful to work with handles and normal addreses uniformly
2714 // C@A+
2715 // ( idx -- byte )
2716 UFWORD(CPEEK_REGA_IDX) {
2717 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2718 const uint32_t idx = ufoPop();
2719 const uint32_t newaddr = ufoRegA + idx;
2720 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK)) {
2721 ufoPush(ufoImgGetU8Ext(newaddr));
2722 } else {
2723 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2724 ufoRegA, idx, newaddr);
2726 } else {
2727 ufoPush(ufoRegA);
2728 UFCALL(PAR_HANDLE_LOAD_BYTE);
2732 // W@A+
2733 // ( idx -- word )
2734 UFWORD(WPEEK_REGA_IDX) {
2735 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2736 const uint32_t idx = ufoPop();
2737 const uint32_t newaddr = ufoRegA + idx;
2738 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
2739 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 1u) & UFO_ADDR_SPECIAL_BITS_MASK))
2741 ufoPush(ufoImgGetU16(newaddr));
2742 } else {
2743 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2744 ufoRegA, idx, newaddr);
2746 } else {
2747 ufoPush(ufoRegA);
2748 UFCALL(PAR_HANDLE_LOAD_WORD);
2752 // @A+
2753 // ( idx -- value )
2754 UFWORD(PEEK_REGA_IDX) {
2755 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2756 const uint32_t idx = ufoPop();
2757 const uint32_t newaddr = ufoRegA + idx;
2758 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
2759 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 3u) & UFO_ADDR_SPECIAL_BITS_MASK))
2761 ufoPush(ufoImgGetU32(newaddr));
2762 } else {
2763 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2764 ufoRegA, idx, newaddr);
2766 } else {
2767 ufoPush(ufoRegA);
2768 UFCALL(PAR_HANDLE_LOAD_CELL);
2772 // C!A+
2773 // ( byte idx -- )
2774 UFWORD(CPOKE_REGA_IDX) {
2775 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2776 const uint32_t idx = ufoPop();
2777 const uint32_t newaddr = ufoRegA + idx;
2778 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK)) {
2779 const uint32_t value = ufoPop();
2780 ufoImgPutU8(newaddr, value);
2781 } else {
2782 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2783 ufoRegA, idx, newaddr);
2785 } else {
2786 ufoPush(ufoRegA);
2787 UFCALL(PAR_HANDLE_STORE_BYTE);
2791 // W!A+
2792 // ( word idx -- )
2793 UFWORD(WPOKE_REGA_IDX) {
2794 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2795 const uint32_t idx = ufoPop();
2796 const uint32_t newaddr = ufoRegA + idx;
2797 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
2798 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 1u) & UFO_ADDR_SPECIAL_BITS_MASK))
2800 const uint32_t value = ufoPop();
2801 ufoImgPutU16(newaddr, value);
2802 } else {
2803 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2804 ufoRegA, idx, newaddr);
2806 } else {
2807 ufoPush(ufoRegA);
2808 UFCALL(PAR_HANDLE_STORE_WORD);
2812 // !A+
2813 // ( value idx -- )
2814 UFWORD(POKE_REGA_IDX) {
2815 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
2816 const uint32_t idx = ufoPop();
2817 const uint32_t newaddr = ufoRegA + idx;
2818 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
2819 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 3u) & UFO_ADDR_SPECIAL_BITS_MASK))
2821 const uint32_t value = ufoPop();
2822 ufoImgPutU32(newaddr, value);
2823 } else {
2824 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2825 ufoRegA, idx, newaddr);
2827 } else {
2828 ufoPush(ufoRegA);
2829 UFCALL(PAR_HANDLE_STORE_CELL);
2834 // ////////////////////////////////////////////////////////////////////////// //
2835 // peeks and pokes
2838 // C@
2839 // ( addr -- value8 )
2840 UFWORD(CPEEK) {
2841 ufoPush(ufoImgGetU8Ext(ufoPop()));
2844 // W@
2845 // ( addr -- value16 )
2846 UFWORD(WPEEK) {
2847 const uint32_t addr = ufoPop();
2848 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
2849 ufoPush(ufoImgGetU16(addr));
2850 } else {
2851 ufoPush(0);
2852 ufoPush(addr);
2853 UFCALL(PAR_HANDLE_LOAD_WORD);
2857 // @
2858 // ( addr -- value32 )
2859 UFWORD(PEEK) {
2860 const uint32_t addr = ufoPop();
2861 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
2862 ufoPush(ufoImgGetU32(addr));
2863 } else {
2864 ufoPush(0);
2865 ufoPush(addr);
2866 UFCALL(PAR_HANDLE_LOAD_CELL);
2870 // C!
2871 // ( val8 addr -- )
2872 UFWORD(CPOKE) {
2873 const uint32_t addr = ufoPop();
2874 const uint32_t val = ufoPop();
2875 ufoImgPutU8Ext(addr, val);
2878 // W!
2879 // ( val16 addr -- )
2880 UFWORD(WPOKE) {
2881 const uint32_t addr = ufoPop();
2882 const uint32_t val = ufoPop();
2883 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
2884 ufoImgPutU16(addr, val);
2885 } else {
2886 ufoPush(val);
2887 ufoPush(0);
2888 ufoPush(addr);
2889 UFCALL(PAR_HANDLE_STORE_WORD);
2893 // !
2894 // ( val32 addr -- )
2895 UFWORD(POKE) {
2896 const uint32_t addr = ufoPop();
2897 const uint32_t val = ufoPop();
2898 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
2899 ufoImgPutU32(addr, val);
2900 } else {
2901 ufoPush(val);
2902 ufoPush(0);
2903 ufoPush(addr);
2904 UFCALL(PAR_HANDLE_STORE_CELL);
2909 // ////////////////////////////////////////////////////////////////////////// //
2910 // dictionary emitters
2913 // C,
2914 // ( val8 -- )
2915 UFWORD(CCOMMA) { const uint32_t val = ufoPop(); ufoImgEmitU8(val); }
2917 // W,
2918 // ( val16 -- )
2919 UFWORD(WCOMMA) { const uint32_t val = ufoPop(); ufoImgEmitU8(val&0xffU); ufoImgEmitU8((val >> 8)&0xffU); }
2921 // ,
2922 // ( val -- )
2923 UFWORD(COMMA) { const uint32_t val = ufoPop(); ufoImgEmitU32(val); }
2926 // ////////////////////////////////////////////////////////////////////////// //
2927 // literal pushers
2931 // (LIT) ( -- n )
2932 UFWORD(PAR_LIT) {
2933 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
2934 ufoPush(v);
2937 // (LITCFA) ( -- n )
2938 UFWORD(PAR_LITCFA) {
2939 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
2940 ufoPush(v);
2943 // (LITVOCID) ( -- n )
2944 UFWORD(PAR_LITVOCID) {
2945 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
2946 ufoPush(v);
2949 // (STRLIT8)
2950 UFWORD(PAR_STRLIT8) {
2951 const uint32_t count = ufoImgGetU8(ufoIP); ufoIP += 1;
2952 ufoPush(ufoIP);
2953 ufoPush(count);
2954 ufoIP += count + 1; // 1 for terminating 0
2955 // align
2956 ufoIP = UFO_ALIGN4(ufoIP);
2960 // ////////////////////////////////////////////////////////////////////////// //
2961 // jumps, etc.
2965 // (BRANCH) ( -- )
2966 UFWORD(PAR_BRANCH) {
2967 ufoIP = ufoImgGetU32(ufoIP);
2970 // (TBRANCH) ( flag )
2971 UFWORD(PAR_TBRANCH) {
2972 if (ufoPop()) {
2973 ufoIP = ufoImgGetU32(ufoIP);
2974 } else {
2975 ufoIP += 4;
2979 // (0BRANCH) ( flag )
2980 UFWORD(PAR_0BRANCH) {
2981 if (!ufoPop()) {
2982 ufoIP = ufoImgGetU32(ufoIP);
2983 } else {
2984 ufoIP += 4;
2989 // ////////////////////////////////////////////////////////////////////////// //
2990 // execute words by CFA
2994 // EXECUTE ( cfa )
2995 UFWORD(EXECUTE) {
2996 ufoRPush(ufoPop());
2997 ufoVMRPopCFA = 1;
3000 // EXECUTE-TAIL ( cfa )
3001 UFWORD(EXECUTE_TAIL) {
3002 ufoIP = ufoRPop();
3003 ufoRPush(ufoPop());
3004 ufoVMRPopCFA = 1;
3008 // ////////////////////////////////////////////////////////////////////////// //
3009 // word termination, locals support
3013 // (EXIT)
3014 UFWORD(PAR_EXIT) {
3015 ufoIP = ufoRPop();
3018 // (L-ENTER)
3019 // ( loccount -- )
3020 UFWORD(PAR_LENTER) {
3021 // low byte of loccount is total number of locals
3022 // high byte is the number of args
3023 uint32_t lcount = ufoImgGetU32(ufoIP); ufoIP += 4u;
3024 uint32_t acount = (lcount >> 8) & 0xff;
3025 lcount &= 0xff;
3026 if (lcount == 0 || lcount < acount) ufoFatal("invalid call to (L-ENTER)");
3027 if ((ufoLBP != 0 && ufoLBP >= ufoLP) || UFO_LSTACK_SIZE - ufoLP <= lcount + 2) {
3028 ufoFatal("out of locals stack");
3030 uint32_t newbp;
3031 if (ufoLP == 0) { ufoLP = 1; newbp = 1; } else newbp = ufoLP;
3032 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3033 ufoLStack[ufoLP] = ufoLBP; ufoLP += 1;
3034 ufoLBP = newbp; ufoLP += lcount;
3035 // and copy args
3036 newbp += acount;
3037 while (newbp != ufoLBP) {
3038 ufoLStack[newbp] = ufoPop();
3039 newbp -= 1;
3043 // (L-LEAVE)
3044 UFWORD(PAR_LLEAVE) {
3045 if (ufoLBP == 0) ufoFatal("(L-LEAVE) with empty locals stack");
3046 if (ufoLBP >= ufoLP) ufoFatal("(L-LEAVE) broken locals stack");
3047 ufoLP = ufoLBP;
3048 ufoLBP = ufoLStack[ufoLBP];
3052 //==========================================================================
3054 // ufoLoadLocal
3056 //==========================================================================
3057 UFO_FORCE_INLINE void ufoLoadLocal (const uint32_t lidx) {
3058 if (lidx == 0 || lidx >= UFO_LSTACK_SIZE) ufoFatal("invalid local index");
3059 if (ufoLBP == 0 || ufoLBP >= ufoLP || ufoLP - ufoLBP <= lidx) ufoFatal("invalid local index");
3060 ufoPush(ufoLStack[ufoLBP + lidx]);
3064 //==========================================================================
3066 // ufoStoreLocal
3068 //==========================================================================
3069 UFO_FORCE_INLINE void ufoStoreLocal (const uint32_t lidx) {
3070 const uint32_t value = ufoPop();
3071 if (lidx == 0 || lidx >= UFO_LSTACK_SIZE) ufoFatal("invalid local index");
3072 if (ufoLBP == 0 || ufoLBP >= ufoLP || ufoLP - ufoLBP <= lidx) ufoFatal("invalid local index");
3073 ufoLStack[ufoLBP + lidx] = value;
3077 // (LOCAL@)
3078 // ( idx -- value )
3079 UFWORD(PAR_LOCAL_LOAD) { ufoLoadLocal(ufoPop()); }
3081 // (LOCAL!)
3082 // ( value idx -- )
3083 UFWORD(PAR_LOCAL_STORE) { ufoStoreLocal(ufoPop()); }
3086 // ////////////////////////////////////////////////////////////////////////// //
3087 // stack manipulation
3091 // DUP
3092 // ( n -- n n )
3093 UFWORD(DUP) { ufoDup(); }
3094 // ?DUP
3095 // ( n -- n n ) | ( 0 -- 0 )
3096 UFWORD(QDUP) { if (ufoPeek()) ufoDup(); }
3097 // 2DUP
3098 // ( n0 n1 -- n0 n1 n0 n1 )
3099 UFWORD(DDUP) { ufo2Dup(); }
3100 // DROP
3101 // ( n -- )
3102 UFWORD(DROP) { ufoDrop(); }
3103 // 2DROP
3104 // ( n0 n1 -- )
3105 UFWORD(DDROP) { ufo2Drop(); }
3106 // SWAP
3107 // ( n0 n1 -- n1 n0 )
3108 UFWORD(SWAP) { ufoSwap(); }
3109 // 2SWAP
3110 // ( n0 n1 -- n1 n0 )
3111 UFWORD(DSWAP) { ufo2Swap(); }
3112 // OVER
3113 // ( n0 n1 -- n0 n1 n0 )
3114 UFWORD(OVER) { ufoOver(); }
3115 // 2OVER
3116 // ( n0 n1 -- n0 n1 n0 )
3117 UFWORD(DOVER) { ufo2Over(); }
3118 // ROT
3119 // ( n0 n1 n2 -- n1 n2 n0 )
3120 UFWORD(ROT) { ufoRot(); }
3121 // NROT
3122 // ( n0 n1 n2 -- n2 n0 n1 )
3123 UFWORD(NROT) { ufoNRot(); }
3125 // RDUP
3126 // ( n -- n n )
3127 UFWORD(RDUP) { ufoRDup(); }
3128 // RDROP
3129 // ( n -- )
3130 UFWORD(RDROP) { ufoRDrop(); }
3132 // >R
3133 // ( n -- | n )
3134 UFWORD(DTOR) { ufoRPush(ufoPop()); }
3135 // R>
3136 // ( | n -- n )
3137 UFWORD(RTOD) { ufoPush(ufoRPop()); }
3138 // R@
3139 // ( | n -- n | n)
3140 UFWORD(RPEEK) { ufoPush(ufoRPeek()); }
3143 // PICK
3144 // ( idx -- n )
3145 UFWORD(PICK) {
3146 const uint32_t n = ufoPop();
3147 if (n >= ufoSP) ufoFatal("invalid PICK index %u", n);
3148 ufoPush(ufoDStack[ufoSP - n - 1u]);
3151 // RPICK
3152 // ( idx -- n )
3153 UFWORD(RPICK) {
3154 const uint32_t n = ufoPop();
3155 if (n >= ufoRP - ufoRPTop) ufoFatal("invalid RPICK index %u", n);
3156 const uint32_t rp = ufoRP - n - 1u;
3157 ufoPush(ufoRStack[rp]);
3160 // ROLL
3161 // ( idx -- n )
3162 UFWORD(ROLL) {
3163 const uint32_t n = ufoPop();
3164 if (n >= ufoSP) ufoFatal("invalid ROLL index %u", n);
3165 switch (n) {
3166 case 0: break; // do nothing
3167 case 1: ufoSwap(); break;
3168 case 2: ufoRot(); break;
3169 default:
3171 const uint32_t val = ufoDStack[ufoSP - n - 1u];
3172 for (uint32_t f = ufoSP - n; f < ufoSP; f += 1) ufoDStack[f - 1] = ufoDStack[f];
3173 ufoDStack[ufoSP - 1u] = val;
3175 break;
3179 // RROLL
3180 // ( idx -- n )
3181 UFWORD(RROLL) {
3182 const uint32_t n = ufoPop();
3183 if (n >= ufoRP - ufoRPTop) ufoFatal("invalid RROLL index %u", n);
3184 if (n != 0) {
3185 const uint32_t rp = ufoRP - n - 1u;
3186 const uint32_t val = ufoRStack[rp];
3187 for (uint32_t f = rp + 1u; f < ufoRP; f += 1u) ufoRStack[f - 1u] = ufoRStack[f];
3188 ufoRStack[ufoRP - 1u] = val;
3192 // RSWAP
3193 // ( | a b -- | b a )
3194 UFWORD(RSWAP) {
3195 const uint32_t b = ufoRPop();
3196 const uint32_t a = ufoRPop();
3197 ufoRPush(b); ufoRPush(a);
3200 // ROVER
3201 // ( | a b -- | a b a )
3202 UFWORD(ROVER) {
3203 const uint32_t b = ufoRPop();
3204 const uint32_t a = ufoRPop();
3205 ufoRPush(a); ufoRPush(b); ufoRPush(a);
3208 // RROT
3209 // ( | a b c -- | b c a )
3210 UFWORD(RROT) {
3211 const uint32_t c = ufoRPop();
3212 const uint32_t b = ufoRPop();
3213 const uint32_t a = ufoRPop();
3214 ufoRPush(b); ufoRPush(c); ufoRPush(a);
3217 // RNROT
3218 // ( | a b c -- | c a b )
3219 UFWORD(RNROT) {
3220 const uint32_t c = ufoRPop();
3221 const uint32_t b = ufoRPop();
3222 const uint32_t a = ufoRPop();
3223 ufoRPush(c); ufoRPush(a); ufoRPush(b);
3227 // ////////////////////////////////////////////////////////////////////////// //
3228 // TIB API
3231 // REFILL
3232 // ( -- eofflag )
3233 UFWORD(REFILL) {
3234 ufoPushBool(ufoLoadNextLine(1));
3237 // REFILL-NOCROSS
3238 // ( -- eofflag )
3239 UFWORD(REFILL_NOCROSS) {
3240 ufoPushBool(ufoLoadNextLine(0));
3243 // (TIB-IN)
3244 // ( -- addr )
3245 UFWORD(TIB_IN) {
3246 ufoPush(ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx));
3249 // TIB-PEEKCH
3250 // ( -- char )
3251 UFWORD(TIB_PEEKCH) {
3252 ufoPush(ufoTibPeekCh());
3255 // TIB-PEEKCH-OFS
3256 // ( ofs -- char )
3257 UFWORD(TIB_PEEKCH_OFS) {
3258 const uint32_t ofs = ufoPop();
3259 ufoPush(ufoTibPeekChOfs(ofs));
3262 // TIB-GETCH
3263 // ( -- char )
3264 UFWORD(TIB_GETCH) {
3265 ufoPush(ufoTibGetCh());
3268 // TIB-SKIPCH
3269 // ( -- )
3270 UFWORD(TIB_SKIPCH) {
3271 ufoTibSkipCh();
3275 // ////////////////////////////////////////////////////////////////////////// //
3276 // TIB parsing
3279 //==========================================================================
3281 // ufoIsDelim
3283 //==========================================================================
3284 UFO_FORCE_INLINE int ufoIsDelim (uint8_t ch, uint8_t delim) {
3285 return (delim == 32 ? (ch <= 32) : (ch == delim));
3289 // (PARSE)
3290 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3291 // does base TIB parsing; never copies anything.
3292 // as our reader is line-based, returns FALSE on EOL.
3293 // EOL is detected after skipping leading delimiters.
3294 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3295 // trailing delimiter is always skipped.
3296 UFWORD(PAR_PARSE) {
3297 const uint32_t skipDelim = ufoPop();
3298 const uint32_t delim = ufoPop();
3299 uint8_t ch;
3301 if (delim == 0 || delim > 0xffU) {
3302 // skip everything
3303 while (ufoTibGetCh() != 0) {}
3304 ufoPushBool(0);
3305 } else {
3306 ch = ufoTibPeekCh();
3307 // skip initial delimiters
3308 if (skipDelim) {
3309 while (ch != 0 && ufoIsDelim(ch, delim)) {
3310 ufoTibSkipCh();
3311 ch = ufoTibPeekCh();
3314 if (ch == 0) {
3315 ufoPushBool(0);
3316 } else {
3317 // parse
3318 const uint32_t staddr = ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx);
3319 uint32_t count = 0;
3320 while (ch != 0 && !ufoIsDelim(ch, delim)) {
3321 count += 1u;
3322 ufoTibSkipCh();
3323 ch = ufoTibPeekCh();
3325 // skip delimiter
3326 if (ch != 0) ufoTibSkipCh();
3327 ufoPush(staddr);
3328 ufoPush(count);
3329 ufoPushBool(1);
3334 // PARSE-SKIP-BLANKS
3335 // ( -- )
3336 UFWORD(PARSE_SKIP_BLANKS) {
3337 uint8_t ch = ufoTibPeekCh();
3338 while (ch != 0 && ch <= 32) {
3339 ufoTibSkipCh();
3340 ch = ufoTibPeekCh();
3345 //==========================================================================
3347 // ufoParseMLComment
3349 // initial two chars are skipped
3351 //==========================================================================
3352 static void ufoParseMLComment (uint32_t allowMulti, int nested) {
3353 uint32_t level = 1;
3354 uint8_t ch, ch1;
3355 while (level != 0) {
3356 ch = ufoTibGetCh();
3357 if (ch == 0) {
3358 if (allowMulti) {
3359 UFCALL(REFILL_NOCROSS);
3360 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3361 } else {
3362 ufoFatal("unexpected end of line in comment");
3364 } else {
3365 ch1 = ufoTibPeekCh();
3366 if (nested && ch == '(' && ch1 == '(') { ufoTibSkipCh(); level += 1; }
3367 else if (nested && ch == ')' && ch1 == ')') { ufoTibSkipCh(); level -= 1; }
3368 else if (!nested && ch == '*' && ch1 == ')') { ufo_assert(level == 1); ufoTibSkipCh(); level = 0; }
3374 // (PARSE-SKIP-COMMENTS)
3375 // ( allow-multiline? -- )
3376 // skip all blanks and comments
3377 UFWORD(PAR_PARSE_SKIP_COMMENTS) {
3378 const uint32_t allowMulti = ufoPop();
3379 uint8_t ch, ch1;
3380 ch = ufoTibPeekCh();
3381 #if 0
3382 fprintf(stderr, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch);
3383 #endif
3384 while (ch != 0) {
3385 if (ch <= 32) {
3386 ufoTibSkipCh();
3387 ch = ufoTibPeekCh();
3388 #if 0
3389 fprintf(stderr, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch);
3390 #endif
3391 } else if (ch == '(') {
3392 #if 0
3393 fprintf(stderr, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch, (char)ch1,
3394 ufoTibPeekChOfs(0));
3395 #endif
3396 ch1 = ufoTibPeekChOfs(1);
3397 if (ch1 <= 32) {
3398 // single-line comment
3399 do { ch = ufoTibGetCh(); } while (ch != 0 && ch != ')');
3400 ch = ufoTibPeekCh();
3401 } else if (ch1 == '*' || ch1 == '(') {
3402 // possibly multiline
3403 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3404 ufoParseMLComment(allowMulti, (ch1 == '('));
3405 ch = ufoTibPeekCh();
3406 } else {
3407 ch = 0;
3409 } else if (ch == '\\' && ufoTibPeekChOfs(1) <= 32) {
3410 // single-line comment
3411 while (ch != 0) ch = ufoTibGetCh();
3412 } else if ((ch == ';' || ch == '-' || ch == '/') && (ufoTibPeekChOfs(1) == ch)) {
3413 // skip to EOL
3414 while (ch != 0) ch = ufoTibGetCh();
3415 } else {
3416 ch = 0;
3419 #if 0
3420 fprintf(stderr, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3421 #endif
3424 // PARSE-SKIP-LINE
3425 // ( -- )
3426 UFWORD(PARSE_SKIP_LINE) {
3427 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE);
3428 if (ufoPop() != 0) {
3429 ufo2Drop();
3433 // PARSE-NAME
3434 // ( -- addr count )
3435 // parse with leading blanks skipping. doesn't copy anything.
3436 // return empty string on EOL.
3437 UFWORD(PARSE_NAME) {
3438 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE);
3439 if (ufoPop() == 0) {
3440 ufoPush(0);
3441 ufoPush(0);
3445 // PARSE
3446 // ( delim -- addr count TRUE / FALSE )
3447 // parse without skipping delimiters; never copies anything.
3448 // as our reader is line-based, returns FALSE on EOL.
3449 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3450 // trailing delimiter is always skipped.
3451 UFWORD(PARSE) {
3452 ufoPushBool(0); UFCALL(PAR_PARSE);
3456 // ////////////////////////////////////////////////////////////////////////// //
3457 // char output
3460 // (NORM-EMIT-CHAR)
3461 // ( ch -- )
3462 UFWORD(PAR_NORM_EMIT_CHAR) {
3463 uint32_t ch = ufoPop()&0xffU;
3464 if (ch < 32 || ch == 127) {
3465 if (ch != 9 && ch != 10 && ch != 13) ch = '?';
3467 ufoPush(ch);
3470 // (NORM-XEMIT-CHAR)
3471 // ( ch -- )
3472 UFWORD(PAR_NORM_XEMIT_CHAR) {
3473 uint32_t ch = ufoPop()&0xffU;
3474 if (ch < 32 || ch == 127) ch = '?';
3475 ufoPush(ch);
3478 // (EMIT)
3479 // ( n -- )
3480 UFWORD(PAR_EMIT) {
3481 uint32_t ch = ufoPop()&0xffU;
3482 ufoLastEmitWasCR = (ch == 10);
3483 putchar((char)ch);
3486 // LASTCR?
3487 // ( -- bool )
3488 UFWORD(LASTCRQ) {
3489 ufoPushBool(ufoLastEmitWasCR);
3492 // LASTCR!
3493 // ( bool -- )
3494 UFWORD(LASTCRSET) {
3495 ufoLastEmitWasCR = !!ufoPop();
3498 // FLUSH-EMIT
3499 // ( -- )
3500 UFWORD(FLUSH_EMIT) {
3501 fflush(NULL);
3505 // ////////////////////////////////////////////////////////////////////////// //
3506 // simple math
3509 #define UF_UMATH(name_,op_) \
3510 UFWORD(name_) { \
3511 const uint32_t a = ufoPop(); \
3512 ufoPush(op_); \
3515 #define UF_BMATH(name_,op_) \
3516 UFWORD(name_) { \
3517 const uint32_t b = ufoPop(); \
3518 const uint32_t a = ufoPop(); \
3519 ufoPush(op_); \
3522 #define UF_BDIV(name_,op_) \
3523 UFWORD(name_) { \
3524 const uint32_t b = ufoPop(); \
3525 const uint32_t a = ufoPop(); \
3526 if (b == 0) ufoFatal("division by zero"); \
3527 ufoPush(op_); \
3530 #define UFO_POP_U64() ({ \
3531 const uint32_t hi_ = ufoPop(); \
3532 const uint32_t lo_ = ufoPop(); \
3533 (((uint64_t)hi_ << 32) | lo_); \
3536 // this is UB by the idiotic C standard. i don't care.
3537 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
3539 #define UFO_PUSH_U64(vn_) do { \
3540 ufoPush((uint32_t)(vn_)); \
3541 ufoPush((uint32_t)((vn_) >> 32)); \
3542 } while (0)
3544 // this is UB by the idiotic C standard. i don't care.
3545 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
3548 // +
3549 // ( a b -- a+b )
3550 UF_BMATH(PLUS, a + b);
3552 // -
3553 // ( a b -- a-b )
3554 UF_BMATH(MINUS, a - b);
3556 // *
3557 // ( a b -- a*b )
3558 UF_BMATH(MUL, (uint32_t)((int32_t)a * (int32_t)b));
3560 // U*
3561 // ( a b -- a*b )
3562 UF_BMATH(UMUL, a * b);
3564 // /
3565 // ( a b -- a/b )
3566 UF_BDIV(DIV, (uint32_t)((int32_t)a / (int32_t)b));
3568 // U/
3569 // ( a b -- a/b )
3570 UF_BDIV(UDIV, a / b);
3572 // MOD
3573 // ( a b -- a%b )
3574 UF_BDIV(MOD, (uint32_t)((int32_t)a % (int32_t)b));
3576 // UMOD
3577 // ( a b -- a%b )
3578 UF_BDIV(UMOD, a % b);
3580 // /MOD
3581 // ( a b -- a/b, a%b )
3582 UFWORD(DIVMOD) {
3583 const int32_t b = (int32_t)ufoPop();
3584 const int32_t a = (int32_t)ufoPop();
3585 if (b == 0) ufoFatal("division by zero");
3586 ufoPush((uint32_t)(a/b));
3587 ufoPush((uint32_t)(a%b));
3590 // U/MOD
3591 // ( a b -- a/b, a%b )
3592 UFWORD(UDIVMOD) {
3593 const uint32_t b = ufoPop();
3594 const uint32_t a = ufoPop();
3595 if (b == 0) ufoFatal("division by zero");
3596 ufoPush((uint32_t)(a/b));
3597 ufoPush((uint32_t)(a%b));
3600 // */
3601 // ( a b c -- a*b/c )
3602 // this uses 64-bit intermediate value
3603 UFWORD(MULDIV) {
3604 const int32_t c = (int32_t)ufoPop();
3605 const int32_t b = (int32_t)ufoPop();
3606 const int32_t a = (int32_t)ufoPop();
3607 if (c == 0) ufoFatal("division by zero");
3608 int64_t xval = a; xval *= b; xval /= c;
3609 ufoPush((uint32_t)(int32_t)xval);
3612 // U*/
3613 // ( a b c -- a*b/c )
3614 // this uses 64-bit intermediate value
3615 UFWORD(UMULDIV) {
3616 const uint32_t c = ufoPop();
3617 const uint32_t b = ufoPop();
3618 const uint32_t a = ufoPop();
3619 if (c == 0) ufoFatal("division by zero");
3620 uint64_t xval = a; xval *= b; xval /= c;
3621 ufoPush((uint32_t)xval);
3624 // */MOD
3625 // ( a b c -- a*b/c a*b%c )
3626 // this uses 64-bit intermediate value
3627 UFWORD(MULDIVMOD) {
3628 const int32_t c = (int32_t)ufoPop();
3629 const int32_t b = (int32_t)ufoPop();
3630 const int32_t a = (int32_t)ufoPop();
3631 if (c == 0) ufoFatal("division by zero");
3632 int64_t xval = a; xval *= b;
3633 ufoPush((uint32_t)(int32_t)(xval / c));
3634 ufoPush((uint32_t)(int32_t)(xval % c));
3637 // U*/
3638 // ( a b c -- a*b/c )
3639 // this uses 64-bit intermediate value
3640 UFWORD(UMULDIVMOD) {
3641 const uint32_t c = ufoPop();
3642 const uint32_t b = ufoPop();
3643 const uint32_t a = ufoPop();
3644 if (c == 0) ufoFatal("division by zero");
3645 uint64_t xval = a; xval *= b;
3646 ufoPush((uint32_t)(xval / c));
3647 ufoPush((uint32_t)(xval % c));
3650 // M*
3651 // ( a b -- lo(a*b) hi(a*b) )
3652 // this leaves 64-bit result
3653 UFWORD(MMUL) {
3654 const int32_t b = (int32_t)ufoPop();
3655 const int32_t a = (int32_t)ufoPop();
3656 int64_t xval = a; xval *= b;
3657 UFO_PUSH_I64(xval);
3660 // UM*
3661 // ( a b -- lo(a*b) hi(a*b) )
3662 // this leaves 64-bit result
3663 UFWORD(UMMUL) {
3664 const uint32_t b = ufoPop();
3665 const uint32_t a = ufoPop();
3666 uint64_t xval = a; xval *= b;
3667 UFO_PUSH_U64(xval);
3670 // M/MOD
3671 // ( alo ahi b -- a/b a%b )
3672 UFWORD(MDIVMOD) {
3673 const int32_t b = (int32_t)ufoPop();
3674 if (b == 0) ufoFatal("division by zero");
3675 int64_t a = UFO_POP_I64();
3676 int32_t adiv = (int32_t)(a / b);
3677 int32_t amod = (int32_t)(a % b);
3678 ufoPush((uint32_t)adiv);
3679 ufoPush((uint32_t)amod);
3682 // UM/MOD
3683 // ( alo ahi b -- a/b a%b )
3684 UFWORD(UMDIVMOD) {
3685 const uint32_t b = ufoPop();
3686 if (b == 0) ufoFatal("division by zero");
3687 uint64_t a = UFO_POP_U64();
3688 uint32_t adiv = (uint32_t)(a / b);
3689 uint32_t amod = (uint32_t)(a % b);
3690 ufoPush(adiv);
3691 ufoPush(amod);
3694 // UDS*
3695 // ( alo ahi u -- lo hi )
3696 UFWORD(UDSMUL) {
3697 const uint32_t b = ufoPop();
3698 uint64_t a = UFO_POP_U64();
3699 a *= b;
3700 UFO_PUSH_U64(a);
3703 // D-
3704 // ( lo0 hi0 lo1 hi1 -- lo hi )
3705 UFWORD(DMINUS) {
3706 uint64_t n1 = UFO_POP_U64();
3707 uint64_t n0 = UFO_POP_U64();
3708 n0 -= n1;
3709 UFO_PUSH_U64(n0);
3712 // D+
3713 // ( lo0 hi0 lo1 hi1 -- lo hi )
3714 UFWORD(DPLUS) {
3715 uint64_t n1 = UFO_POP_U64();
3716 uint64_t n0 = UFO_POP_U64();
3717 n0 += n1;
3718 UFO_PUSH_U64(n0);
3721 // D=
3722 // ( lo0 hi0 lo1 hi1 -- bool )
3723 UFWORD(DEQU) {
3724 uint64_t n1 = UFO_POP_U64();
3725 uint64_t n0 = UFO_POP_U64();
3726 ufoPushBool(n0 == n1);
3729 // D<
3730 // ( lo0 hi0 lo1 hi1 -- bool )
3731 UFWORD(DLESS) {
3732 int64_t n1 = UFO_POP_I64();
3733 int64_t n0 = UFO_POP_I64();
3734 ufoPushBool(n0 < n1);
3737 // D<=
3738 // ( lo0 hi0 lo1 hi1 -- bool )
3739 UFWORD(DLESSEQU) {
3740 int64_t n1 = UFO_POP_I64();
3741 int64_t n0 = UFO_POP_I64();
3742 ufoPushBool(n0 <= n1);
3745 // DU<
3746 // ( lo0 hi0 lo1 hi1 -- bool )
3747 UFWORD(DULESS) {
3748 uint64_t n1 = UFO_POP_U64();
3749 uint64_t n0 = UFO_POP_U64();
3750 ufoPushBool(n0 < n1);
3753 // DU<=
3754 // ( lo0 hi0 lo1 hi1 -- bool )
3755 UFWORD(DULESSEQU) {
3756 uint64_t n1 = UFO_POP_U64();
3757 uint64_t n0 = UFO_POP_U64();
3758 ufoPushBool(n0 <= n1);
3761 // SM/REM
3762 // ( dlo dhi n -- nmod ndiv )
3763 // rounds toward zero
3764 UFWORD(SMREM) {
3765 const int32_t n = (int32_t)ufoPop();
3766 if (n == 0) ufoFatal("division by zero");
3767 int64_t d = UFO_POP_I64();
3768 int32_t ndiv = (int32_t)(d / n);
3769 int32_t nmod = (int32_t)(d % n);
3770 ufoPush(nmod);
3771 ufoPush(ndiv);
3774 // FM/MOD
3775 // ( dlo dhi n -- nmod ndiv )
3776 // rounds toward negative infinity
3777 UFWORD(FMMOD) {
3778 const int32_t n = (int32_t)ufoPop();
3779 if (n == 0) ufoFatal("division by zero");
3780 int64_t d = UFO_POP_I64();
3781 int32_t ndiv = (int32_t)(d / n);
3782 int32_t nmod = (int32_t)(d % n);
3783 if (nmod != 0 && ((uint32_t)n ^ (uint32_t)(d >> 32)) >= 0x80000000u) {
3784 ndiv -= 1;
3785 nmod += n;
3787 ufoPush(nmod);
3788 ufoPush(ndiv);
3792 // ////////////////////////////////////////////////////////////////////////// //
3793 // simple logic and bit manipulation
3796 #define UF_CMP(name_,op_) \
3797 UFWORD(name_) { \
3798 const uint32_t b = ufoPop(); \
3799 const uint32_t a = ufoPop(); \
3800 ufoPushBool(op_); \
3803 // <
3804 // ( a b -- a<b )
3805 UF_CMP(LESS, (int32_t)a < (int32_t)b);
3807 // U<
3808 // ( a b -- a<b )
3809 UF_CMP(ULESS, a < b);
3811 // >
3812 // ( a b -- a>b )
3813 UF_CMP(GREAT, (int32_t)a > (int32_t)b);
3815 // U>
3816 // ( a b -- a>b )
3817 UF_CMP(UGREAT, a > b);
3819 // <=
3820 // ( a b -- a<=b )
3821 UF_CMP(LESSEQU, (int32_t)a <= (int32_t)b);
3823 // U<=
3824 // ( a b -- a<=b )
3825 UF_CMP(ULESSEQU, a <= b);
3827 // >=
3828 // ( a b -- a>=b )
3829 UF_CMP(GREATEQU, (int32_t)a >= (int32_t)b);
3831 // U>=
3832 // ( a b -- a>=b )
3833 UF_CMP(UGREATEQU, a >= b);
3835 // =
3836 // ( a b -- a=b )
3837 UF_CMP(EQU, a == b);
3839 // <>
3840 // ( a b -- a<>b )
3841 UF_CMP(NOTEQU, a != b);
3843 // NOT
3844 // ( a -- !a )
3845 UFWORD(NOT) {
3846 const uint32_t a = ufoPop();
3847 ufoPushBool(!a);
3850 // LAND
3851 // ( a b -- a&&b )
3852 UF_CMP(LOGAND, a && b);
3854 // LOR
3855 // ( a b -- a||b )
3856 UF_CMP(LOGOR, a || b);
3858 // AND
3859 // ( a b -- a&b )
3860 UFWORD(AND) {
3861 const uint32_t b = ufoPop();
3862 const uint32_t a = ufoPop();
3863 ufoPush(a&b);
3866 // OR
3867 // ( a b -- a|b )
3868 UFWORD(OR) {
3869 const uint32_t b = ufoPop();
3870 const uint32_t a = ufoPop();
3871 ufoPush(a|b);
3874 // XOR
3875 // ( a b -- a^b )
3876 UFWORD(XOR) {
3877 const uint32_t b = ufoPop();
3878 const uint32_t a = ufoPop();
3879 ufoPush(a^b);
3882 // BITNOT
3883 // ( a -- ~a )
3884 UFWORD(BITNOT) {
3885 const uint32_t a = ufoPop();
3886 ufoPush(~a);
3889 UFWORD(ONESHL) { uint32_t n = ufoPop(); ufoPush(n << 1); }
3890 UFWORD(ONESHR) { uint32_t n = ufoPop(); ufoPush(n >> 1); }
3891 UFWORD(TWOSHL) { uint32_t n = ufoPop(); ufoPush(n << 2); }
3892 UFWORD(TWOSHR) { uint32_t n = ufoPop(); ufoPush(n >> 2); }
3894 // ASH
3895 // ( n count -- )
3896 // arithmetic shift; positive `n` shifts to the left
3897 UFWORD(ASH) {
3898 int32_t c = (int32_t)ufoPop();
3899 if (c < 0) {
3900 // right
3901 int32_t n = (int32_t)ufoPop();
3902 if (c < -30) {
3903 if (n < 0) n = -1; else n = 0;
3904 } else {
3905 n >>= (uint8_t)(-c);
3907 ufoPush((uint32_t)n);
3908 } else if (c > 0) {
3909 // left
3910 uint32_t u = ufoPop();
3911 if (c > 31) {
3912 u = 0;
3913 } else {
3914 u <<= (uint8_t)c;
3916 ufoPush(u);
3920 // LSH
3921 // ( n count -- )
3922 // logical shift; positive `n` shifts to the left
3923 UFWORD(LSH) {
3924 int32_t c = (int32_t) ufoPop();
3925 uint32_t u = ufoPop();
3926 if (c < 0) {
3927 // right
3928 if (c < -31) {
3929 u = 0;
3930 } else {
3931 u >>= (uint8_t)(-c);
3933 } else if (c > 0) {
3934 // left
3935 if (c > 31) {
3936 u = 0;
3937 } else {
3938 u <<= (uint8_t)c;
3941 ufoPush(u);
3945 // ////////////////////////////////////////////////////////////////////////// //
3946 // string unescaping
3949 // (UNESCAPE)
3950 // ( addr count -- addr count )
3951 UFWORD(PAR_UNESCAPE) {
3952 const uint32_t count = ufoPop();
3953 const uint32_t addr = ufoPeek();
3954 if ((count & ((uint32_t)1<<31)) == 0) {
3955 const uint32_t eaddr = addr + count;
3956 uint32_t caddr = addr;
3957 uint32_t daddr = addr;
3958 while (caddr != eaddr) {
3959 uint8_t ch = ufoImgGetU8Ext(caddr); caddr += 1u;
3960 if (ch == '\\' && caddr != eaddr) {
3961 ch = ufoImgGetU8Ext(caddr); caddr += 1u;
3962 switch (ch) {
3963 case 'r': ch = '\r'; break;
3964 case 'n': ch = '\n'; break;
3965 case 't': ch = '\t'; break;
3966 case 'e': ch = '\x1b'; break;
3967 case '`': ch = '"'; break; // special escape to insert double-quote
3968 case '"': ch = '"'; break;
3969 case '\\': ch = '\\'; break;
3970 case 'x': case 'X':
3971 if (eaddr - daddr >= 1) {
3972 const int dg0 = digitInBase((char)(ufoImgGetU8Ext(caddr)), 16);
3973 if (dg0 < 0) ufoFatal("invalid hex string escape");
3974 if (eaddr - daddr >= 2) {
3975 const int dg1 = digitInBase((char)(ufoImgGetU8Ext(caddr + 1u)), 16);
3976 if (dg1 < 0) ufoFatal("invalid hex string escape");
3977 ch = (uint8_t)(dg0 * 16 + dg1);
3978 caddr += 2u;
3979 } else {
3980 ch = (uint8_t)dg0;
3981 caddr += 1u;
3983 } else {
3984 ufoFatal("invalid hex string escape");
3986 break;
3987 default: ufoFatal("invalid string escape");
3990 ufoImgPutU8Ext(daddr, ch); daddr += 1u;
3992 ufoPush(daddr - addr);
3993 } else {
3994 ufoPush(count);
3999 // ////////////////////////////////////////////////////////////////////////// //
4000 // numeric conversions
4003 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4004 UFWORD(PAR_BASED_NUMBER) {
4005 const uint32_t xbase = ufoPop();
4006 const uint32_t allowSign = ufoPop();
4007 int32_t count = (int32_t)ufoPop();
4008 uint32_t addr = ufoPop();
4009 uint32_t n = 0;
4010 int base = 0;
4011 int neg = 0;
4012 uint8_t ch;
4014 if (allowSign && count > 1) {
4015 ch = ufoImgGetU8Ext(addr);
4016 if (ch == '-') { neg = 1; addr += 1u; count -= 1; }
4017 else if (ch == '+') { neg = 0; addr += 1u; count -= 1; }
4020 // special-based numbers
4021 if (count >= 3 && ufoImgGetU8Ext(addr) == '0') {
4022 switch (ufoImgGetU8Ext(addr + 1u)) {
4023 case 'x': case 'X': base = 16; break;
4024 case 'o': case 'O': base = 8; break;
4025 case 'b': case 'B': base = 2; break;
4026 case 'd': case 'D': base = 10; break;
4027 default: break;
4029 if (base) { addr += 2; count -= 2; }
4030 } else if (count >= 2 && ufoImgGetU8Ext(addr) == '$') {
4031 base = 16;
4032 addr += 1; count -= 1;
4033 } else if (count >= 2 && ufoImgGetU8Ext(addr) == '#') {
4034 base = 16;
4035 addr += 1; count -= 1;
4036 } else if (count >= 2 && ufoImgGetU8Ext(addr) == '%') {
4037 base = 2;
4038 addr += 1; count -= 1;
4039 } else if (count >= 3 && ufoImgGetU8Ext(addr) == '&') {
4040 switch (ufoImgGetU8Ext(addr + 1u)) {
4041 case 'h': case 'H': base = 16; break;
4042 case 'o': case 'O': base = 8; break;
4043 case 'b': case 'B': base = 2; break;
4044 case 'd': case 'D': base = 10; break;
4045 default: break;
4047 if (base) { addr += 2; count -= 2; }
4048 } else if (xbase < 12 && count > 2 && toUpperU8(ufoImgGetU8Ext(addr + (uint32_t)count - 1u)) == 'B') {
4049 base = 2;
4050 count -= 1;
4051 } else if (xbase < 18 && count > 2 && toUpperU8(ufoImgGetU8Ext(addr + (uint32_t)count - 1u)) == 'H') {
4052 base = 16;
4053 count -= 1;
4054 } else if (xbase < 25 && count > 2 && toUpperU8(ufoImgGetU8Ext(addr + (uint32_t)count - 1u)) == 'O') {
4055 base = 8;
4056 count -= 1;
4059 // in current base?
4060 if (!base && xbase < 255) base = xbase;
4062 if (count <= 0 || base < 1 || base > 36) {
4063 ufoPushBool(0);
4064 } else {
4065 uint32_t nc;
4066 int wasDig = 0, wasUnder = 1, error = 0, dig;
4067 while (!error && count != 0) {
4068 ch = ufoImgGetU8Ext(addr); addr += 1u; count -= 1;
4069 if (ch != '_') {
4070 error = 1; wasUnder = 0; wasDig = 1;
4071 dig = digitInBase((char)ch, (int)base);
4072 if (dig >= 0) {
4073 nc = n * (uint32_t)base;
4074 if (nc >= n) {
4075 nc += (uint32_t)dig;
4076 if (nc >= n) {
4077 n = nc;
4078 error = 0;
4082 } else {
4083 error = wasUnder;
4084 wasUnder = 1;
4088 if (!error && wasDig && !wasUnder) {
4089 if (allowSign && neg) n = ~n + 1u;
4090 ufoPush(n);
4091 ufoPushBool(1);
4092 } else {
4093 ufoPushBool(0);
4099 // ////////////////////////////////////////////////////////////////////////// //
4100 // compiler-related, dictionary-related
4103 static char ufoWNameBuf[256];
4106 // [
4107 UFWORD(LBRACKET_IMM) {
4108 if (ufoImgGetU32(ufoAddrSTATE) == 0) ufoFatal("expects compiling mode");
4109 ufoImgPutU32(ufoAddrSTATE, 0);
4112 // ]
4113 UFWORD(RBRACKET) {
4114 if (ufoImgGetU32(ufoAddrSTATE) != 0) ufoFatal("expects interpreting mode");
4115 ufoImgPutU32(ufoAddrSTATE, 1);
4118 // (CREATE-WORD-HEADER)
4119 // ( addr count word-flags -- )
4120 UFWORD(PAR_CREATE_WORD_HEADER) {
4121 const uint32_t flags = ufoPop();
4122 const uint32_t wlen = ufoPop();
4123 const uint32_t waddr = ufoPop();
4124 if (wlen == 0) ufoFatal("word name expected");
4125 if (wlen >= UFO_MAX_WORD_LENGTH) ufoFatal("word name too long");
4126 // copy to separate buffer
4127 for (uint32_t f = 0; f < wlen; f += 1) {
4128 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4130 ufoWNameBuf[wlen] = 0;
4131 ufoCreateWordHeader(ufoWNameBuf, flags);
4134 // (CREATE-NAMELESS-WORD-HEADER)
4135 // ( word-flags -- )
4136 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER) {
4137 const uint32_t flags = ufoPop();
4138 ufoCreateWordHeader("", flags);
4141 // FIND-WORD
4142 // ( addr count -- cfa TRUE / FALSE)
4143 UFWORD(FIND_WORD) {
4144 const uint32_t wlen = ufoPop();
4145 const uint32_t waddr = ufoPop();
4146 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4147 // copy to separate buffer
4148 for (uint32_t f = 0; f < wlen; f += 1) {
4149 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4151 ufoWNameBuf[wlen] = 0;
4152 const uint32_t cfa = ufoFindWord(ufoWNameBuf);
4153 if (cfa != 0) {
4154 ufoPush(cfa);
4155 ufoPushBool(1);
4156 } else {
4157 ufoPushBool(0);
4159 } else {
4160 ufoPushBool(0);
4164 // FIND-WORD-IN-VOC
4165 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4166 // find only in the given voc; no name resolution
4167 UFWORD(FIND_WORD_IN_VOC) {
4168 const uint32_t allowHidden = ufoPop();
4169 const uint32_t vocid = ufoPop();
4170 const uint32_t wlen = ufoPop();
4171 const uint32_t waddr = ufoPop();
4172 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4173 // copy to separate buffer
4174 for (uint32_t f = 0; f < wlen; f += 1) {
4175 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4177 ufoWNameBuf[wlen] = 0;
4178 const uint32_t cfa = ufoFindWordInVoc(ufoWNameBuf, wlen, 0, vocid, (allowHidden ? 1 : 0));
4179 if (cfa != 0) {
4180 ufoPush(cfa);
4181 ufoPushBool(1);
4182 } else {
4183 ufoPushBool(0);
4185 } else {
4186 ufoPushBool(0);
4190 // FIND-WORD-IN-VOC-AND-PARENTS
4191 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4192 // find only in the given voc; no name resolution
4193 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS) {
4194 const uint32_t allowHidden = ufoPop();
4195 const uint32_t vocid = ufoPop();
4196 const uint32_t wlen = ufoPop();
4197 const uint32_t waddr = ufoPop();
4198 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4199 // copy to separate buffer
4200 for (uint32_t f = 0; f < wlen; f += 1) {
4201 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4203 ufoWNameBuf[wlen] = 0;
4204 const uint32_t cfa = ufoFindWordInVocAndParents(ufoWNameBuf, wlen, 0, vocid, (allowHidden ? 1 : 0));
4205 if (cfa != 0) {
4206 ufoPush(cfa);
4207 ufoPushBool(1);
4208 } else {
4209 ufoPushBool(0);
4211 } else {
4212 ufoPushBool(0);
4217 // ////////////////////////////////////////////////////////////////////////// //
4218 // more compiler words
4221 // ?EXEC
4222 UFWORD(QEXEC) {
4223 if (ufoImgGetU32(ufoAddrSTATE) != 0) ufoFatal("expecting execution mode");
4226 // ?COMP
4227 UFWORD(QCOMP) {
4228 if (ufoImgGetU32(ufoAddrSTATE) == 0) ufoFatal("expecting compilation mode");
4231 // "
4232 // string literal
4233 UFWORD(QUOTE_IMM) {
4234 ufoPush(34); UFCALL(PARSE);
4235 if (ufoPop() == 0) ufoFatal("string literal expected");
4236 UFCALL(PAR_UNESCAPE);
4237 if (ufoImgGetU32(ufoAddrSTATE) != 0) {
4238 // compiling
4239 const uint32_t wlen = ufoPop();
4240 const uint32_t waddr = ufoPop();
4241 if (wlen > 255) ufoFatal("string literal too long");
4242 ufoImgEmitU32(ufoStrLit8CFA);
4243 ufoImgEmitU8(wlen);
4244 for (uint32_t f = 0; f < wlen; f += 1) {
4245 ufoImgEmitU8(ufoImgGetU8Ext(waddr + f));
4247 ufoImgEmitU8(0);
4248 ufoImgEmitAlign();
4253 // ////////////////////////////////////////////////////////////////////////// //
4254 // vocabulary and wordlist utilities
4257 // (VSP@)
4258 // ( -- vsp )
4259 UFWORD(PAR_GET_VSP) {
4260 ufoPush(ufoVSP);
4263 // (VSP!)
4264 // ( vsp -- )
4265 UFWORD(PAR_SET_VSP) {
4266 const uint32_t vsp = ufoPop();
4267 if (vsp >= UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4268 ufoVSP = vsp;
4271 // (VSP-AT@)
4272 // ( idx -- value )
4273 UFWORD(PAR_VSP_LOAD) {
4274 const uint32_t vsp = ufoPop();
4275 if (vsp >= UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4276 ufoPush(ufoVocStack[vsp]);
4279 // (VSP-AT!)
4280 // ( value idx -- )
4281 UFWORD(PAR_VSP_STORE) {
4282 const uint32_t vsp = ufoPop();
4283 const uint32_t value = ufoPop();
4284 if (vsp > UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4285 ufoVocStack[vsp] = value;
4289 // ////////////////////////////////////////////////////////////////////////// //
4290 // word field address conversion
4293 // CFA->PFA
4294 // ( cfa -- pfa )
4295 UFWORD(CFA2PFA) {
4296 const uint32_t cfa = ufoPop();
4297 ufoPush(UFO_CFA_TO_PFA(cfa));
4300 // PFA->CFA
4301 // ( pfa -- cfa )
4302 UFWORD(PFA2CFA) {
4303 const uint32_t pfa = ufoPop();
4304 ufoPush(UFO_PFA_TO_CFA(pfa));
4307 // CFA->NFA
4308 // ( cfa -- nfa )
4309 UFWORD(CFA2NFA) {
4310 const uint32_t cfa = ufoPop();
4311 ufoPush(UFO_CFA_TO_NFA(cfa));
4314 // NFA->CFA
4315 // ( nfa -- cfa )
4316 UFWORD(NFA2CFA) {
4317 const uint32_t nfa = ufoPop();
4318 ufoPush(UFO_NFA_TO_CFA(nfa));
4321 // CFA->LFA
4322 // ( cfa -- lfa )
4323 UFWORD(CFA2LFA) {
4324 const uint32_t cfa = ufoPop();
4325 ufoPush(UFO_CFA_TO_LFA(cfa));
4328 // LFA->CFA
4329 // ( lfa -- cfa )
4330 UFWORD(LFA2CFA) {
4331 const uint32_t lfa = ufoPop();
4332 ufoPush(UFO_LFA_TO_CFA(lfa));
4335 // LFA->PFA
4336 // ( lfa -- pfa )
4337 UFWORD(LFA2PFA) {
4338 const uint32_t lfa = ufoPop();
4339 const uint32_t cfa = UFO_LFA_TO_CFA(lfa);
4340 ufoPush(UFO_CFA_TO_PFA(cfa));
4343 // LFA->BFA
4344 // ( lfa -- bfa )
4345 UFWORD(LFA2BFA) {
4346 const uint32_t lfa = ufoPop();
4347 ufoPush(UFO_LFA_TO_BFA(lfa));
4350 // LFA->XFA
4351 // ( lfa -- xfa )
4352 UFWORD(LFA2XFA) {
4353 const uint32_t lfa = ufoPop();
4354 ufoPush(UFO_LFA_TO_XFA(lfa));
4357 // LFA->YFA
4358 // ( lfa -- yfa )
4359 UFWORD(LFA2YFA) {
4360 const uint32_t lfa = ufoPop();
4361 ufoPush(UFO_LFA_TO_YFA(lfa));
4364 // LFA->NFA
4365 // ( lfa -- nfa )
4366 UFWORD(LFA2NFA) {
4367 const uint32_t lfa = ufoPop();
4368 ufoPush(UFO_LFA_TO_NFA(lfa));
4371 // NFA->LFA
4372 // ( nfa -- lfa )
4373 UFWORD(NFA2LFA) {
4374 const uint32_t nfa = ufoPop();
4375 ufoPush(UFO_NFA_TO_LFA(nfa));
4378 // CFA->WEND
4379 // ( cfa -- wend-addr )
4380 UFWORD(CFA2WEND) {
4381 const uint32_t cfa = ufoPop();
4382 ufoPush(ufoGetWordEndAddr(cfa));
4385 // IP->NFA
4386 // ( ip -- nfa / 0 )
4387 UFWORD(IP2NFA) {
4388 const uint32_t ip = ufoPop();
4389 ufoPush(ufoFindWordForIP(ip));
4392 // IP->FILE/LINE
4393 // ( ip -- addr count line TRUE / FALSE )
4394 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4395 UFWORD(IP2FILELINE) {
4396 const uint32_t ip = ufoPop();
4397 uint32_t fline;
4398 const char *fname = ufoFindFileForIP(ip, &fline);
4399 if (fname != NULL) {
4400 UFCALL(PAD);
4401 const uint32_t addr = ufoPeek();
4402 uint32_t count = 0;
4403 while (*fname != 0) {
4404 ufoImgPutU8(addr + count, *(const unsigned char *)fname);
4405 fname += 1u; count += 1u;
4407 ufoImgPutU8(addr + count, 0); // just in case
4408 ufoPush(addr);
4409 ufoPush(count);
4410 ufoPushBool(1);
4411 } else {
4412 ufoPushBool(0);
4417 // ////////////////////////////////////////////////////////////////////////// //
4418 // string operations
4421 UFO_FORCE_INLINE uint32_t ufoHashBuf (uint32_t addr, uint32_t size, uint8_t orbyte) {
4422 uint32_t hash = 0x29a;
4423 if ((size & ((uint32_t)1<<31)) == 0) {
4424 while (size != 0) {
4425 hash += ufoImgGetU8Ext(addr) | orbyte;
4426 hash += hash<<10;
4427 hash ^= hash>>6;
4428 addr += 1u; size -= 1u;
4431 // finalize
4432 hash += hash<<3;
4433 hash ^= hash>>11;
4434 hash += hash<<15;
4435 return hash;
4438 //==========================================================================
4440 // ufoBufEqu
4442 //==========================================================================
4443 UFO_FORCE_INLINE int ufoBufEqu (uint32_t addr0, uint32_t addr1, uint32_t count) {
4444 int res;
4445 if ((count & ((uint32_t)1<<31)) == 0) {
4446 res = 1;
4447 while (res != 0 && count != 0) {
4448 res = (toUpperU8(ufoImgGetU8Ext(addr0)) == toUpperU8(ufoImgGetU8Ext(addr1)));
4449 addr0 += 1u; addr1 += 1u; count -= 1u;
4451 } else {
4452 res = 0;
4454 return res;
4457 // STRING:=
4458 // ( a0 c0 a1 c1 -- bool )
4459 UFWORD(STREQU) {
4460 int32_t c1 = (int32_t)ufoPop();
4461 uint32_t a1 = ufoPop();
4462 int32_t c0 = (int32_t)ufoPop();
4463 uint32_t a0 = ufoPop();
4464 if (c0 < 0) c0 = 0;
4465 if (c1 < 0) c1 = 0;
4466 if (c0 == c1) {
4467 int res = 1;
4468 while (res != 0 && c0 != 0) {
4469 res = (ufoImgGetU8Ext(a0) == ufoImgGetU8Ext(a1));
4470 a0 += 1; a1 += 1; c0 -= 1;
4472 ufoPushBool(res);
4473 } else {
4474 ufoPushBool(0);
4478 // STRING:=CI
4479 // ( a0 c0 a1 c1 -- bool )
4480 UFWORD(STREQUCI) {
4481 int32_t c1 = (int32_t)ufoPop();
4482 uint32_t a1 = ufoPop();
4483 int32_t c0 = (int32_t)ufoPop();
4484 uint32_t a0 = ufoPop();
4485 if (c0 < 0) c0 = 0;
4486 if (c1 < 0) c1 = 0;
4487 if (c0 == c1) {
4488 int res = 1;
4489 while (res != 0 && c0 != 0) {
4490 res = (toUpperU8(ufoImgGetU8Ext(a0)) == toUpperU8(ufoImgGetU8Ext(a1)));
4491 a0 += 1; a1 += 1; c0 -= 1;
4493 ufoPushBool(res);
4494 } else {
4495 ufoPushBool(0);
4499 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4500 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4501 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4502 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4503 UFWORD(SEARCH) {
4504 const uint32_t pcount = ufoPop();
4505 const uint32_t paddr = ufoPop();
4506 const uint32_t tcount = ufoPop();
4507 const uint32_t taddr = ufoPop();
4508 if ((pcount & ((uint32_t)1 << 31)) == 0 && (tcount & ((uint32_t)1 << 31)) == 0) {
4509 for (uint32_t f = 0; tcount - f >= pcount; f += 1) {
4510 if (ufoBufEqu(taddr + f, paddr, pcount)) {
4511 ufoPush(taddr + f);
4512 ufoPush(tcount - f);
4513 ufoPushBool(1);
4514 return;
4518 ufoPush(taddr);
4519 ufoPush(tcount);
4520 ufoPushBool(0);
4523 // STRING:HASH
4524 // ( addr count -- hash )
4525 UFWORD(STRHASH) {
4526 uint32_t count = ufoPop();
4527 uint32_t addr = ufoPop();
4528 ufoPush(ufoHashBuf(addr, count, 0));
4531 // STRING:HASH-CI
4532 // ( addr count -- hash )
4533 UFWORD(STRHASHCI) {
4534 uint32_t count = ufoPop();
4535 uint32_t addr = ufoPop();
4536 ufoPush(ufoHashBuf(addr, count, 0x20));
4540 // ////////////////////////////////////////////////////////////////////////// //
4541 // conditional defines
4544 typedef struct UForthCondDefine_t UForthCondDefine;
4545 struct UForthCondDefine_t {
4546 char *name;
4547 uint32_t namelen;
4548 uint32_t hash;
4549 UForthCondDefine *next;
4552 static UForthCondDefine *ufoCondDefines = NULL;
4553 static char ufoErrMsgBuf[4096];
4556 //==========================================================================
4558 // ufoStrEquCI
4560 //==========================================================================
4561 UFO_DISABLE_INLINE int ufoStrEquCI (const void *str0, const void *str1) {
4562 const unsigned char *s0 = (const unsigned char *)str0;
4563 const unsigned char *s1 = (const unsigned char *)str1;
4564 while (*s0 && *s1) {
4565 if (toUpperU8(*s0) != toUpperU8(*s1)) return 0;
4566 s0 += 1; s1 += 1;
4568 return (*s0 == 0 && *s1 == 0);
4572 //==========================================================================
4574 // ufoBufEquCI
4576 //==========================================================================
4577 UFO_FORCE_INLINE int ufoBufEquCI (uint32_t addr, uint32_t count, const void *buf) {
4578 int res;
4579 if ((count & ((uint32_t)1<<31)) == 0) {
4580 const unsigned char *src = (const unsigned char *)buf;
4581 res = 1;
4582 while (res != 0 && count != 0) {
4583 res = (toUpperU8(*src) == toUpperU8(ufoImgGetU8Ext(addr)));
4584 src += 1; addr += 1u; count -= 1u;
4586 } else {
4587 res = 0;
4589 return res;
4593 //==========================================================================
4595 // ufoClearCondDefines
4597 //==========================================================================
4598 static void ufoClearCondDefines (void) {
4599 while (ufoCondDefines) {
4600 UForthCondDefine *df = ufoCondDefines;
4601 ufoCondDefines = df->next;
4602 if (df->name) free(df->name);
4603 free(df);
4608 //==========================================================================
4610 // ufoHasCondDefine
4612 //==========================================================================
4613 int ufoHasCondDefine (const char *name) {
4614 int res = 0;
4615 if (name != NULL && name[0] != 0) {
4616 const size_t nlen = strlen(name);
4617 if (nlen <= 255) {
4618 const uint32_t hash = joaatHashBufCI(name, nlen);
4619 UForthCondDefine *dd = ufoCondDefines;
4620 while (res == 0 && dd != NULL) {
4621 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
4622 res = ufoStrEquCI(name, dd->name);
4624 dd = dd->next;
4628 return res;
4632 //==========================================================================
4634 // ufoCondDefine
4636 //==========================================================================
4637 void ufoCondDefine (const char *name) {
4638 if (name != NULL && name[0] != 0) {
4639 const size_t nlen = strlen(name);
4640 if (nlen > 255) ufoFatal("conditional define name too long");
4641 const uint32_t hash = joaatHashBufCI(name, nlen);
4642 UForthCondDefine *dd = ufoCondDefines;
4643 int res = 0;
4644 while (res == 0 && dd != NULL) {
4645 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
4646 res = ufoStrEquCI(name, dd->name);
4648 dd = dd->next;
4650 if (res == 0) {
4651 // new define
4652 dd = calloc(1, sizeof(UForthCondDefine));
4653 if (dd == NULL) ufoFatal("out of memory for defines");
4654 dd->name = strdup(name);
4655 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
4656 dd->namelen = (uint32_t)nlen;
4657 dd->hash = hash;
4658 dd->next = ufoCondDefines;
4659 ufoCondDefines = dd;
4665 //==========================================================================
4667 // ufoCondUndef
4669 //==========================================================================
4670 void ufoCondUndef (const char *name) {
4671 if (name != NULL && name[0] != 0) {
4672 const size_t nlen = strlen(name);
4673 if (nlen <= 255) {
4674 const uint32_t hash = joaatHashBufCI(name, nlen);
4675 UForthCondDefine *dd = ufoCondDefines;
4676 UForthCondDefine *prev = NULL;
4677 while (dd != NULL) {
4678 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
4679 if (ufoStrEquCI(name, dd->name)) {
4680 if (prev != NULL) prev->next = dd->next; else ufoCondDefines = dd->next;
4681 free(dd->name);
4682 free(dd);
4683 dd = NULL;
4686 if (dd != NULL) { prev = dd; dd = dd->next; }
4693 // ($DEFINE)
4694 // ( addr count -- )
4695 UFWORD(PAR_DLR_DEFINE) {
4696 uint32_t count = ufoPop();
4697 uint32_t addr = ufoPop();
4698 if (count == 0) ufoFatal("empty define");
4699 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
4700 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
4701 UForthCondDefine *dd;
4702 for (dd = ufoCondDefines; dd != NULL; dd = dd->next) {
4703 if (dd->hash == hash && dd->namelen == count) {
4704 if (ufoBufEquCI(addr, count, dd->name)) return;
4707 // new define
4708 dd = calloc(1, sizeof(UForthCondDefine));
4709 if (dd == NULL) ufoFatal("out of memory for defines");
4710 dd->name = calloc(1, count + 1u);
4711 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
4712 for (uint32_t f = 0; f < count; f += 1) {
4713 ((unsigned char *)dd->name)[f] = ufoImgGetU8Ext(addr + f);
4715 dd->namelen = count;
4716 dd->hash = hash;
4717 dd->next = ufoCondDefines;
4718 ufoCondDefines = dd;
4721 // ($UNDEF)
4722 // ( addr count -- )
4723 UFWORD(PAR_DLR_UNDEF) {
4724 uint32_t count = ufoPop();
4725 uint32_t addr = ufoPop();
4726 if (count == 0) ufoFatal("empty define");
4727 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
4728 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
4729 UForthCondDefine *prev = NULL;
4730 UForthCondDefine *dd;
4731 for (dd = ufoCondDefines; dd != NULL; prev = dd, dd = dd->next) {
4732 if (dd->hash == hash && dd->namelen == count) {
4733 if (ufoBufEquCI(addr, count, dd->name)) {
4734 if (prev == NULL) ufoCondDefines = dd->next; else prev->next = dd->next;
4735 free(dd->name);
4736 free(dd);
4737 return;
4743 // ($DEFINED?)
4744 // ( addr count -- bool )
4745 UFWORD(PAR_DLR_DEFINEDQ) {
4746 uint32_t count = ufoPop();
4747 uint32_t addr = ufoPop();
4748 if (count == 0) ufoFatal("empty define");
4749 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
4750 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
4751 int found = 0;
4752 UForthCondDefine *dd = ufoCondDefines;
4753 while (!found && dd != NULL) {
4754 if (dd->hash == hash && dd->namelen == count) {
4755 found = ufoBufEquCI(addr, count, dd->name);
4757 dd = dd->next;
4759 ufoPushBool(found);
4763 // ////////////////////////////////////////////////////////////////////////// //
4764 // error reporting
4767 // ERROR
4768 // ( addr count -- )
4769 UFWORD(ERROR) {
4770 uint32_t count = ufoPop();
4771 uint32_t addr = ufoPop();
4772 if (count & (1u<<31)) ufoFatal("invalid error message");
4773 if (count == 0) ufoFatal("some error");
4774 if (count > (uint32_t)sizeof(ufoErrMsgBuf) - 1u) count = (uint32_t)sizeof(ufoErrMsgBuf) - 1u;
4775 for (uint32_t f = 0; f < count; f += 1) {
4776 ufoErrMsgBuf[f] = (char)ufoImgGetU8Ext(addr + f);
4778 ufoErrMsgBuf[count] = 0;
4779 ufoFatal("%s", ufoErrMsgBuf);
4782 // ?ERROR
4783 // ( errflag addr count -- )
4784 UFWORD(QERROR) {
4785 const uint32_t count = ufoPop();
4786 const uint32_t addr = ufoPop();
4787 if (ufoPop()) {
4788 ufoPush(addr);
4789 ufoPush(count);
4790 UFCALL(ERROR);
4795 // ////////////////////////////////////////////////////////////////////////// //
4796 // includes
4799 static char ufoFNameBuf[4096];
4802 //==========================================================================
4804 // ufoScanIncludeFileName
4806 // `*psys` and `*psoft` must be initialised!
4808 //==========================================================================
4809 static void ufoScanIncludeFileName (uint32_t addr, uint32_t count, char *dest, size_t destsz,
4810 uint32_t *psys, uint32_t *psoft)
4812 uint8_t ch;
4813 uint32_t dpos;
4814 ufo_assert(dest != NULL);
4815 ufo_assert(destsz > 0);
4817 while (count != 0) {
4818 ch = ufoImgGetU8Ext(addr);
4819 if (ch == '!') {
4820 //if (system) ufoFatal("invalid file name (duplicate system mark)");
4821 *psys = 1;
4822 } else if (ch == '?') {
4823 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
4824 *psoft = 1;
4825 } else {
4826 break;
4828 do {
4829 addr += 1; count -= 1;
4830 ch = ufoImgGetU8Ext(addr);
4831 } while (ch <= 32 && count != 0);
4834 if (count == 0) ufoFatal("empty include file name");
4835 if (count >= destsz) ufoFatal("include file name too long");
4837 dpos = 0;
4838 while (count != 0) {
4839 dest[dpos] = (char)ufoImgGetU8Ext(addr); dpos += 1;
4840 addr += 1; count -= 1;
4842 dest[dpos] = 0;
4846 // (INCLUDE-DEPTH)
4847 // ( -- depth )
4848 // return number of items in include stack
4849 UFWORD(PAR_INCLUDE_DEPTH) {
4850 ufoPush(ufoFileStackPos);
4853 // (INCLUDE-FILE-ID)
4854 // ( isp -- id ) -- isp 0 is current, then 1, etc.
4855 // each include file has unique non-zero id.
4856 UFWORD(PAR_INCLUDE_FILE_ID) {
4857 const uint32_t isp = ufoPop();
4858 if (isp == 0) {
4859 ufoPush(ufoFileId);
4860 } else if (isp <= ufoFileStackPos) {
4861 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
4862 ufoPush(stk->id);
4863 } else {
4864 ufoFatal("invalid include stack index");
4868 // (INCLUDE-FILE-LINE)
4869 // ( isp -- line )
4870 UFWORD(PAR_INCLUDE_FILE_LINE) {
4871 const uint32_t isp = ufoPop();
4872 if (isp == 0) {
4873 ufoPush(ufoInFileLine);
4874 } else if (isp <= ufoFileStackPos) {
4875 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
4876 ufoPush(stk->fline);
4877 } else {
4878 ufoFatal("invalid include stack index");
4880 ufoPush(ufoInFileLine);
4883 // (INCLUDE-FILE-NAME)
4884 // ( isp -- addr count )
4885 // current file name; at PAD
4886 UFWORD(PAR_INCLUDE_FILE_NAME) {
4887 const uint32_t isp = ufoPop();
4888 const char *fname = NULL;
4889 if (isp == 0) {
4890 fname = ufoInFileName;
4891 } else if (isp <= ufoFileStackPos) {
4892 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
4893 fname = stk->fname;
4894 } else {
4895 ufoFatal("invalid include stack index");
4897 UFCALL(PAD);
4898 uint32_t addr = ufoPop();
4899 uint32_t count = 0;
4900 while (fname[count] != 0) {
4901 ufoImgPutU8Ext(addr + count, ((const unsigned char *)fname)[count]);
4902 count += 1;
4904 ufoImgPutU8Ext(addr + count, 0);
4905 ufoPush(addr);
4906 ufoPush(count);
4909 // (INCLUDE)
4910 // ( addr count soft? system? -- )
4911 UFWORD(PAR_INCLUDE) {
4912 uint32_t system = ufoPop();
4913 uint32_t softinclude = ufoPop();
4914 uint32_t count = ufoPop();
4915 uint32_t addr = ufoPop();
4917 if (ufoMode == UFO_MODE_MACRO) ufoFatal("macros cannot include files");
4919 if ((count & ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
4921 ufoScanIncludeFileName(addr, count, ufoFNameBuf, sizeof(ufoFNameBuf),
4922 &system, &softinclude);
4924 char *ffn = ufoCreateIncludeName(ufoFNameBuf, system, (system ? ufoLastSysIncPath : ufoLastIncPath));
4925 #ifdef WIN32
4926 FILE *fl = fopen(ffn, "rb");
4927 #else
4928 FILE *fl = fopen(ffn, "r");
4929 #endif
4930 if (!fl) {
4931 if (softinclude) { free(ffn); return; }
4932 ufoFatal("include file '%s' not found", ffn);
4934 ufoPushInFile();
4935 ufoInFile = fl;
4936 ufoInFileLine = 0;
4937 ufoInFileName = ffn;
4938 ufoFileId = ufoLastUsedFileId;
4939 setLastIncPath(ufoInFileName, system);
4940 #ifdef UFO_DEBUG_INCLUDE
4941 fprintf(stderr, "INC-PUSH: new fname: %s\n", ffn);
4942 #endif
4944 // trigger next line loading
4945 UFCALL(REFILL);
4946 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
4949 // $INCLUDE "str"
4950 UFWORD(DLR_INCLUDE_IMM) {
4951 int soft = 0, system = 0;
4952 // parse include filename
4953 //UFCALL(PARSE_SKIP_BLANKS);
4954 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
4955 uint8_t ch = ufoTibPeekCh();
4956 if (ch == '"') {
4957 ufoTibSkipCh(); // skip quote
4958 ufoPush(34);
4959 } else if (ch == '<') {
4960 ufoTibSkipCh(); // skip quote
4961 ufoPush(62);
4962 system = 1;
4963 } else {
4964 ufoFatal("expected quoted string");
4966 UFCALL(PARSE);
4967 if (!ufoPop()) ufoFatal("file name expected");
4968 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
4969 if (ufoTibPeekCh() != 0) {
4970 ufoFatal("$INCLUDE doesn't accept extra args yet");
4972 // ( addr count soft? system? -- )
4973 ufoPushBool(soft); ufoPushBool(system); UFCALL(PAR_INCLUDE);
4977 //==========================================================================
4979 // ufoCreateFileGuard
4981 //==========================================================================
4982 static const char *ufoCreateFileGuard (const char *fname) {
4983 if (fname == NULL || fname[0] == 0) return NULL;
4984 char *rp = ufoRealPath(fname);
4985 if (rp == NULL) return NULL;
4986 #ifdef WIN32
4987 for (char *s = rp; *s; s += 1) if (*s == '\\') *s = '/';
4988 #endif
4989 // hash the buffer; extract file name; create string with path len, file name, and hash
4990 const size_t orgplen = strlen(rp);
4991 const uint32_t phash = joaatHashBuf(rp, orgplen, 0);
4992 size_t plen = orgplen;
4993 while (plen != 0 && rp[plen - 1u] != '/') plen -= 1;
4994 snprintf(ufoRealPathHashBuf, sizeof(ufoRealPathHashBuf),
4995 "__INCLUDE_GUARD_%08X_%08X_%s__", phash, (uint32_t)orgplen, rp + plen);
4996 return ufoRealPathHashBuf;
5000 // $INCLUDE-ONCE "str"
5001 // includes file only once; unreliable on shitdoze, i believe
5002 UFWORD(DLR_INCLUDE_ONCE_IMM) {
5003 uint32_t softinclude = 0, system = 0;
5004 // parse include filename
5005 //UFCALL(PARSE_SKIP_BLANKS);
5006 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5007 uint8_t ch = ufoTibPeekCh();
5008 if (ch == '"') {
5009 ufoTibSkipCh(); // skip quote
5010 ufoPush(34);
5011 } else if (ch == '<') {
5012 ufoTibSkipCh(); // skip quote
5013 ufoPush(62);
5014 system = 1;
5015 } else {
5016 ufoFatal("expected quoted string");
5018 UFCALL(PARSE);
5019 if (!ufoPop()) ufoFatal("file name expected");
5020 const uint32_t count = ufoPop();
5021 const uint32_t addr = ufoPop();
5022 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5023 if (ufoTibPeekCh() != 0) {
5024 ufoFatal("$REQUIRE doesn't accept extra args yet");
5026 ufoScanIncludeFileName(addr, count, ufoRealPathHashBuf, sizeof(ufoRealPathHashBuf),
5027 &system, &softinclude);
5028 char *incfname = ufoCreateIncludeName(ufoRealPathHashBuf, system, (system ? ufoLastSysIncPath : ufoLastIncPath));
5029 if (incfname == NULL) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf);
5030 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5031 // this will overwrite `ufoRealPathHashBuf`
5032 const char *guard = ufoCreateFileGuard(incfname);
5033 free(incfname);
5034 if (guard == NULL) {
5035 if (!softinclude) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf);
5036 return;
5038 #if 0
5039 fprintf(stderr, "GUARD: <%s>\n", guard);
5040 #endif
5041 // now check for the guard
5042 const uint32_t glen = (uint32_t)strlen(guard);
5043 const uint32_t ghash = joaatHashBuf(guard, glen, 0);
5044 UForthCondDefine *dd;
5045 for (dd = ufoCondDefines; dd != NULL; dd = dd->next) {
5046 if (dd->hash == ghash && dd->namelen == glen && strcmp(guard, dd->name) == 0) {
5047 // nothing to do: already included
5048 return;
5051 // add guard
5052 dd = calloc(1, sizeof(UForthCondDefine));
5053 if (dd == NULL) ufoFatal("out of memory for defines");
5054 dd->name = calloc(1, glen + 1u);
5055 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
5056 strcpy(dd->name, guard);
5057 dd->namelen = glen;
5058 dd->hash = ghash;
5059 dd->next = ufoCondDefines;
5060 ufoCondDefines = dd;
5061 // ( addr count soft? system? -- )
5062 ufoPush(addr); ufoPush(count); ufoPushBool(softinclude); ufoPushBool(system);
5063 UFCALL(PAR_INCLUDE);
5067 // ////////////////////////////////////////////////////////////////////////// //
5068 // handles
5071 // HANDLE:NEW
5072 // ( typeid -- hx )
5073 UFWORD(PAR_NEW_HANDLE) {
5074 const uint32_t typeid = ufoPop();
5075 if (typeid == UFO_HANDLE_FREE) ufoFatal("invalid handle typeid");
5076 UfoHandle *hh = ufoAllocHandle(typeid);
5077 ufoPush(hh->ufoHandle);
5080 // HANDLE:FREE
5081 // ( hx -- )
5082 UFWORD(PAR_FREE_HANDLE) {
5083 const uint32_t hx = ufoPop();
5084 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("trying to free something that is not a handle");
5085 UfoHandle *hh = ufoGetHandle(hx);
5086 if (hh == NULL) ufoFatal("trying to free invalid handle");
5087 ufoFreeHandle(hh);
5090 // HANDLE:TYPEID@
5091 // ( hx -- typeid )
5092 UFWORD(PAR_HANDLE_GET_TYPEID) {
5093 const uint32_t hx = ufoPop();
5094 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5095 UfoHandle *hh = ufoGetHandle(hx);
5096 if (hh == NULL) ufoFatal("invalid handle");
5097 ufoPush(hh->typeid);
5100 // HANDLE:TYPEID!
5101 // ( typeid hx -- )
5102 UFWORD(PAR_HANDLE_SET_TYPEID) {
5103 const uint32_t hx = ufoPop();
5104 const uint32_t typeid = ufoPop();
5105 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5106 if (typeid == UFO_HANDLE_FREE) ufoFatal("invalid handle typeid");
5107 UfoHandle *hh = ufoGetHandle(hx);
5108 if (hh == NULL) ufoFatal("invalid handle");
5109 hh->typeid = typeid;
5112 // HANDLE:SIZE@
5113 // ( hx -- size )
5114 UFWORD(PAR_HANDLE_GET_SIZE) {
5115 const uint32_t hx = ufoPop();
5116 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5117 UfoHandle *hh = ufoGetHandle(hx);
5118 if (hh == NULL) ufoFatal("invalid handle");
5119 ufoPush(hh->size);
5122 // HANDLE:SIZE!
5123 // ( size hx -- )
5124 UFWORD(PAR_HANDLE_SET_SIZE) {
5125 const uint32_t hx = ufoPop();
5126 const uint32_t size = ufoPop();
5127 if (size > 0x04000000) ufoFatal("invalid handle size");
5128 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5129 UfoHandle *hh = ufoGetHandle(hx);
5130 if (hh == NULL) ufoFatal("invalid handle");
5131 if (hh->size != size) {
5132 if (size == 0) {
5133 free(hh->data);
5134 hh->data = NULL;
5135 } else {
5136 uint8_t *nx = realloc(hh->data, size * sizeof(hh->data[0]));
5137 if (nx == NULL) ufoFatal("out of memory for handle of size %u", size);
5138 hh->data = nx;
5139 if (size > hh->size) memset(hh->data, 0, size - hh->size);
5141 hh->size = size;
5142 if (hh->used > size) hh->used = size;
5146 // HANDLE:USED@
5147 // ( hx -- used )
5148 UFWORD(PAR_HANDLE_GET_USED) {
5149 const uint32_t hx = ufoPop();
5150 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5151 UfoHandle *hh = ufoGetHandle(hx);
5152 if (hh == NULL) ufoFatal("invalid handle");
5153 ufoPush(hh->used);
5156 // HANDLE:USED!
5157 // ( size hx -- )
5158 UFWORD(PAR_HANDLE_SET_USED) {
5159 const uint32_t hx = ufoPop();
5160 const uint32_t used = ufoPop();
5161 if (used > 0x04000000) ufoFatal("invalid handle used");
5162 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5163 UfoHandle *hh = ufoGetHandle(hx);
5164 if (hh == NULL) ufoFatal("invalid handle");
5165 if (used > hh->size) ufoFatal("handle used %u out of range (%u)", used, hh->size);
5166 hh->used = used;
5169 #define POP_PREPARE_HANDLE() \
5170 const uint32_t hx = ufoPop(); \
5171 uint32_t idx = ufoPop(); \
5172 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5173 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5174 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5175 UfoHandle *hh = ufoGetHandle(hx); \
5176 if (hh == NULL) ufoFatal("invalid handle")
5178 // HANDLE:C@
5179 // ( idx hx -- value )
5180 UFWORD(PAR_HANDLE_LOAD_BYTE) {
5181 POP_PREPARE_HANDLE();
5182 if (idx >= hh->size) ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5183 ufoPush(hh->data[idx]);
5186 // HANDLE:W@
5187 // ( idx hx -- value )
5188 UFWORD(PAR_HANDLE_LOAD_WORD) {
5189 POP_PREPARE_HANDLE();
5190 if (idx >= hh->size || hh->size - idx < 2u) {
5191 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5193 #ifdef UFO_FAST_MEM_ACCESS
5194 ufoPush(*(const uint16_t *)(hh->data + idx));
5195 #else
5196 uint32_t res = hh->data[idx];
5197 res |= hh->data[idx + 1u] << 8;
5198 ufoPush(res);
5199 #endif
5202 // HANDLE:@
5203 // ( idx hx -- value )
5204 UFWORD(PAR_HANDLE_LOAD_CELL) {
5205 POP_PREPARE_HANDLE();
5206 if (idx >= hh->size || hh->size - idx < 4u) {
5207 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5209 #ifdef UFO_FAST_MEM_ACCESS
5210 ufoPush(*(const uint32_t *)(hh->data + idx));
5211 #else
5212 uint32_t res = hh->data[idx];
5213 res |= hh->data[idx + 1u] << 8;
5214 res |= hh->data[idx + 2u] << 16;
5215 res |= hh->data[idx + 3u] << 24;
5216 ufoPush(res);
5217 #endif
5220 // HANDLE:C!
5221 // ( value idx hx -- value )
5222 UFWORD(PAR_HANDLE_STORE_BYTE) {
5223 POP_PREPARE_HANDLE();
5224 const uint32_t value = ufoPop();
5225 if (idx >= hh->size) ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5226 hh->data[idx] = value;
5229 // HANDLE:W!
5230 // ( value idx hx -- )
5231 UFWORD(PAR_HANDLE_STORE_WORD) {
5232 POP_PREPARE_HANDLE();
5233 const uint32_t value = ufoPop();
5234 if (idx >= hh->size || hh->size - idx < 2u) {
5235 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5237 #ifdef UFO_FAST_MEM_ACCESS
5238 *(uint16_t *)(hh->data + idx) = (uint16_t)value;
5239 #else
5240 hh->data[idx] = (uint8_t)value;
5241 hh->data[idx + 1u] = (uint8_t)(value >> 8);
5242 #endif
5245 // HANDLE:!
5246 // ( value idx hx -- )
5247 UFWORD(PAR_HANDLE_STORE_CELL) {
5248 POP_PREPARE_HANDLE();
5249 const uint32_t value = ufoPop();
5250 if (idx >= hh->size || hh->size - idx < 4u) {
5251 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5253 #ifdef UFO_FAST_MEM_ACCESS
5254 *(uint32_t *)(hh->data + idx) = value;
5255 #else
5256 hh->data[idx] = (uint8_t)value;
5257 hh->data[idx + 1u] = (uint8_t)(value >> 8);
5258 hh->data[idx + 2u] = (uint8_t)(value >> 16);
5259 hh->data[idx + 3u] = (uint8_t)(value >> 24);
5260 #endif
5264 // HANDLE:LOAD-FILE
5265 // ( addr count -- stx )
5266 UFWORD(PAR_HANDLE_LOAD_FILE) {
5267 uint32_t count = ufoPop();
5268 uint32_t addr = ufoPop();
5270 if ((count & ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5272 uint8_t *dest = (uint8_t *)ufoFNameBuf;
5273 while (count != 0 && dest < (uint8_t *)ufoFNameBuf + sizeof(ufoFNameBuf)) {
5274 uint8_t ch = ufoImgGetU8Ext(addr);
5275 *dest = ch;
5276 dest += 1u; addr += 1u; count -= 1u;
5278 if (dest == (uint8_t *)ufoFNameBuf + sizeof(ufoFNameBuf)) ufoFatal("file name too long");
5279 *dest = 0;
5281 if (*ufoFNameBuf == 0) ufoFatal("empty file name");
5283 char *ffn = ufoCreateIncludeName(ufoFNameBuf, 0/*system*/, ufoLastIncPath);
5284 #ifdef WIN32
5285 FILE *fl = fopen(ffn, "rb");
5286 #else
5287 FILE *fl = fopen(ffn, "r");
5288 #endif
5289 if (!fl) {
5290 ufoFatal("file '%s' not found", ffn);
5293 if (fseek(fl, 0, SEEK_END) != 0) {
5294 fclose(fl);
5295 ufoFatal("seek error in file '%s'", ffn);
5298 long sz = ftell(fl);
5299 if (sz < 0 || sz >= 1024 * 1024 * 64) {
5300 fclose(fl);
5301 ufoFatal("tell error in file '%s' (or too big)", ffn);
5304 if (fseek(fl, 0, SEEK_SET) != 0) {
5305 fclose(fl);
5306 ufoFatal("seek error in file '%s'", ffn);
5309 UfoHandle *hh = ufoAllocHandle(0);
5310 if (sz != 0) {
5311 hh->data = malloc((uint32_t)sz);
5312 if (hh->data == NULL) {
5313 fclose(fl);
5314 ufoFatal("out of memory for file '%s'", ffn);
5316 hh->size = (uint32_t)sz;
5317 if (fread(hh->data, (uint32_t)sz, 1, fl) != 1) {
5318 fclose(fl);
5319 ufoFatal("error reading file '%s'", ffn);
5321 fclose(fl);
5324 free(ffn);
5325 ufoPush(hh->ufoHandle);
5329 // ////////////////////////////////////////////////////////////////////////// //
5330 // utils
5333 // DEBUG:(DECOMPILE-CFA)
5334 // ( cfa -- )
5335 UFWORD(DEBUG_DECOMPILE_CFA) {
5336 const uint32_t cfa = ufoPop();
5337 ufoDecompileWord(cfa);
5340 // GET-MSECS
5341 // ( -- u32 )
5342 UFWORD(GET_MSECS) {
5343 ufoPush((uint32_t)ufo_get_msecs());
5346 // this is called by INTERPRET when it is out of input stream
5347 UFWORD(UFO_INTERPRET_FINISHED_ACTION) {
5348 ufoVMStop = 1;
5351 // MTASK:NEW-STATE
5352 // ( cfa -- stid )
5353 UFWORD(MT_NEW_STATE) {
5354 UfoState *st = ufoNewState(ufoPop());
5355 ufoInitStateUserVars(st, 1);
5356 ufoPush(st->id);
5359 // MTASK:FREE-STATE
5360 // ( stid -- )
5361 UFWORD(MT_FREE_STATE) {
5362 UfoState *st = ufoFindState(ufoPop());
5363 if (st == NULL) ufoFatal("cannot free unknown state");
5364 if (st == ufoCurrState) ufoFatal("cannot free current state");
5365 ufoFreeState(st);
5368 // MTASK:STATE-NAME@
5369 // ( stid -- addr count )
5370 // to PAD
5371 UFWORD(MT_GET_STATE_NAME) {
5372 UfoState *st = ufoFindState(ufoPop());
5373 if (st == NULL) ufoFatal("unknown state");
5374 UFCALL(PAD);
5375 uint32_t addr = ufoPop();
5376 uint32_t count = 0;
5377 while (st->name[count] != 0) {
5378 ufoImgPutU8Ext(addr + count, ((const unsigned char *)st->name)[count]);
5379 count += 1u;
5381 ufoImgPutU8Ext(addr + count, 0);
5382 ufoPush(addr);
5383 ufoPush(count);
5386 // MTASK:STATE-NAME!
5387 // ( addr count stid -- )
5388 UFWORD(MT_SET_STATE_NAME) {
5389 UfoState *st = ufoFindState(ufoPop());
5390 if (st == NULL) ufoFatal("unknown state");
5391 uint32_t count = ufoPop();
5392 uint32_t addr = ufoPop();
5393 if ((count & ((uint32_t)1 << 31)) == 0) {
5394 if (count > UFO_MAX_TASK_NAME) ufoFatal("task name too long");
5395 for (uint32_t f = 0; f < count; f += 1u) {
5396 ((unsigned char *)st->name)[f] = ufoImgGetU8Ext(addr + f);
5398 st->name[count] = 0;
5402 // MTASK:STATE-FIRST
5403 // ( -- stid )
5404 UFWORD(MT_STATE_FIRST) {
5405 uint32_t fidx = 0;
5406 while (fidx != (uint32_t)(UFO_MAX_STATES/32) && ufoStateUsedBitmap[fidx] == 0) fidx += 1u;
5407 // there should be at least one allocated state
5408 ufo_assert(fidx != (uint32_t)(UFO_MAX_STATES/32));
5409 uint32_t bmp = ufoStateUsedBitmap[fidx];
5410 fidx *= 32u;
5411 while ((bmp & 0x01) == 0) { fidx += 1u; bmp >>= 1; }
5412 ufoPush(fidx + 1u);
5415 // MTASK:STATE-NEXT
5416 // ( stid -- stid / 0 )
5417 UFWORD(MT_STATE_NEXT) {
5418 uint32_t stid = ufoPop();
5419 if (stid != 0 && stid < (uint32_t)(UFO_MAX_STATES/32)) {
5420 // it is already incremented for us, yay!
5421 uint32_t fidx = stid / 32u;
5422 uint8_t fofs = stid & 0x1f;
5423 while (fidx < (uint32_t)(UFO_MAX_STATES/32)) {
5424 const uint32_t bmp = ufoStateUsedBitmap[fidx];
5425 if (bmp != 0) {
5426 while (fofs != 32u) {
5427 if ((bmp & ((uint32_t)1 << (fofs & 0x1f))) == 0) fofs += 1u;
5429 if (fofs != 32u) {
5430 ufoPush(fidx * 32u + fofs + 1u);
5431 return; // sorry!
5434 fidx += 1u; fofs = 0;
5437 ufoPush(0);
5441 // MTASK:YIELD-TO
5442 // ( ... argc stid -- )
5443 UFWORD(MT_YIELD_TO) {
5444 UfoState *st = ufoFindState(ufoPop());
5445 if (st == NULL) ufoFatal("cannot yield to unknown state");
5446 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5447 const uint32_t argc = ufoPop();
5448 if (argc > 256) ufoFatal("too many YIELD-TO arguments");
5449 UfoState *curst = ufoCurrState;
5450 if (st != ufoCurrState) {
5451 for (uint32_t f = 0; f < argc; f += 1) {
5452 ufoCurrState = curst;
5453 const uint32_t n = ufoPop();
5454 ufoCurrState = st;
5455 ufoPush(n);
5457 ufoCurrState = curst; // we need to use API call to switch states
5459 ufoSwitchToState(st); // always use API call for this!
5460 ufoPush(argc);
5461 ufoPush(curst->id);
5464 // MTASK:SET-SELF-AS-DEBUGGER
5465 // ( -- )
5466 UFWORD(MT_SET_SELF_AS_DEBUGGER) {
5467 ufoDebuggerState = ufoCurrState;
5470 // DEBUG:(BP)
5471 // ( -- )
5472 // debugger task receives debugge stid on the data stack, and -1 as argc.
5473 // i.e. debugger stask is: ( -1 old-stid )
5474 UFWORD(MT_DEBUGGER_BP) {
5475 if (ufoDebuggerState != NULL && ufoCurrState != ufoDebuggerState) {
5476 UfoState *st = ufoCurrState;
5477 ufoSwitchToState(ufoDebuggerState); // always use API call for this!
5478 ufoPush(-1);
5479 ufoPush(st->id);
5480 ufoSingleStep = 0;
5484 // MTASK:DEBUGGER-RESUME
5485 // ( stid -- )
5486 UFWORD(MT_RESUME_DEBUGEE) {
5487 if (ufoCurrState != ufoDebuggerState) ufoFatal("cannot resume from non-debugger");
5488 UfoState *st = ufoFindState(ufoPop());
5489 if (st == NULL) ufoFatal("cannot yield to unknown state");
5490 if (st == ufoCurrState) ufoFatal("cannot resume into debugger itself");
5491 ufoSwitchToState(st); // always use API call for this!
5492 ufoSingleStep = 0;
5495 // MTASK:DEBUGGER-SINGLE-STEP
5496 // ( stid -- )
5497 UFWORD(MT_SINGLE_STEP_DEBUGEE) {
5498 if (ufoCurrState != ufoDebuggerState) ufoFatal("cannot resume from non-debugger");
5499 UfoState *st = ufoFindState(ufoPop());
5500 if (st == NULL) ufoFatal("cannot yield to unknown state");
5501 if (st == ufoCurrState) ufoFatal("cannot resume into debugger itself");
5502 ufoSwitchToState(st); // always use API call for this!
5503 ufoSingleStep = 2; // it will be decremented after returning from this word
5506 // MTASK:STATE-IP@
5507 // ( stid -- ip )
5508 UFWORD(MT_STATE_IP_GET) {
5509 UfoState *st = ufoFindState(ufoPop());
5510 if (st == NULL) ufoFatal("unknown state");
5511 ufoPush(st->IP);
5514 // MTASK:STATE-IP!
5515 // ( ip stid -- )
5516 UFWORD(MT_STATE_IP_SET) {
5517 UfoState *st = ufoFindState(ufoPop());
5518 if (st == NULL) ufoFatal("unknown state");
5519 st->IP = ufoPop();
5522 // MTASK:STATE-A>
5523 // ( stid -- ip )
5524 UFWORD(MT_STATE_REGA_GET) {
5525 UfoState *st = ufoFindState(ufoPop());
5526 if (st == NULL) ufoFatal("unknown state");
5527 ufoPush(st->regA);
5530 // MTASK:STATE->A
5531 // ( ip stid -- )
5532 UFWORD(MT_STATE_REGA_SET) {
5533 UfoState *st = ufoFindState(ufoPop());
5534 if (st == NULL) ufoFatal("unknown state");
5535 st->regA = ufoPop();
5538 // MTASK:STATE-USER@
5539 // ( addr stid -- value )
5540 UFWORD(MT_STATE_USER_GET) {
5541 UfoState *st = ufoFindState(ufoPop());
5542 if (st == NULL) ufoFatal("unknown state");
5543 uint32_t addr = ufoPop();
5544 if ((addr & UFO_ADDR_TEMP_BIT) != 0 && (addr & UFO_ADDR_TEMP_MASK) + 3u < st->imageTempSize) {
5545 uint32_t v = *(const uint32_t *)((const uint8_t *)st->imageTemp + (addr & UFO_ADDR_TEMP_MASK));
5546 ufoPush(v);
5547 } else {
5548 ufoFatal("invalid user area address");
5552 // MTASK:STATE-USER!
5553 // ( value addr stid -- )
5554 UFWORD(MT_STATE_USER_SET) {
5555 UfoState *st = ufoFindState(ufoPop());
5556 if (st == NULL) ufoFatal("unknown state");
5557 uint32_t addr = ufoPop();
5558 uint32_t value = ufoPop();
5559 if ((addr & UFO_ADDR_TEMP_BIT) != 0 && (addr & UFO_ADDR_TEMP_MASK) + 3u < st->imageTempSize) {
5560 *(uint32_t *)((const uint8_t *)st->imageTemp + (addr & UFO_ADDR_TEMP_MASK)) = value;
5561 } else {
5562 ufoFatal("invalid user area address");
5566 // MTASK:STATE-RPOPCFA@
5567 // ( -- flag )
5568 UFWORD(MT_STATE_RPOPCFA_GET) {
5569 UfoState *st = ufoFindState(ufoPop());
5570 if (st == NULL) ufoFatal("unknown state");
5571 ufoPush(st->vmRPopCFA);
5574 // MTASK:STATE-RPOPCFA!
5575 // ( flag -- )
5576 UFWORD(MT_STATE_RPOPCFA_SET) {
5577 UfoState *st = ufoFindState(ufoPop());
5578 if (st == NULL) ufoFatal("unknown state");
5579 st->vmRPopCFA = ufoPop();
5582 // MTASK:ACTIVE-STATE
5583 // ( -- stid )
5584 UFWORD(MT_ACTIVE_STATE) {
5585 ufoPush(ufoCurrState->id);
5588 // MTASK:YIELDED-FROM
5589 // ( -- stid / 0 )
5590 UFWORD(MT_YIELDED_FROM) {
5591 if (ufoYieldedState != NULL) {
5592 ufoPush(ufoYieldedState->id);
5593 } else {
5594 ufoPush(0);
5598 // MTASK:STATE-SP@
5599 // ( stid -- depth )
5600 UFWORD(MT_DSTACK_DEPTH_GET) {
5601 UfoState *st = ufoFindState(ufoPop());
5602 if (st == NULL) ufoFatal("unknown state");
5603 ufoPush(st->SP);
5606 // MTASK:STATE-RP@
5607 // ( stid -- depth )
5608 UFWORD(MT_RSTACK_DEPTH_GET) {
5609 UfoState *st = ufoFindState(ufoPop());
5610 if (st == NULL) ufoFatal("unknown state");
5611 ufoPush(st->RP - st->RPTop);
5614 // MTASK:STATE-LP@
5615 // ( stid -- lp )
5616 UFWORD(MT_LP_GET) {
5617 UfoState *st = ufoFindState(ufoPop());
5618 if (st == NULL) ufoFatal("unknown state");
5619 ufoPush(st->LP);
5622 // MTASK:STATE-LBP@
5623 // ( stid -- lbp )
5624 UFWORD(MT_LBP_GET) {
5625 UfoState *st = ufoFindState(ufoPop());
5626 if (st == NULL) ufoFatal("unknown state");
5627 ufoPush(st->LBP);
5630 // MTASK:STATE-SP!
5631 // ( depth stid -- )
5632 UFWORD(MT_DSTACK_DEPTH_SET) {
5633 UfoState *st = ufoFindState(ufoPop());
5634 if (st == NULL) ufoFatal("unknown state");
5635 uint32_t idx = ufoPop();
5636 if (idx >= UFO_DSTACK_SIZE) ufoFatal("invalid stack index %u (%u)", idx, UFO_DSTACK_SIZE);
5637 st->SP = idx;
5640 // MTASK:STATE-RP!
5641 // ( stid -- depth )
5642 UFWORD(MT_RSTACK_DEPTH_SET) {
5643 UfoState *st = ufoFindState(ufoPop());
5644 if (st == NULL) ufoFatal("unknown state");
5645 uint32_t idx = ufoPop();
5646 const uint32_t left = UFO_RSTACK_SIZE - st->RPTop;
5647 if (idx >= left) ufoFatal("invalid stack index %u (%u)", idx, left);
5648 st->RP = st->RPTop + idx;
5651 // MTASK:STATE-LP!
5652 // ( lp stid -- )
5653 UFWORD(MT_LP_SET) {
5654 UfoState *st = ufoFindState(ufoPop());
5655 if (st == NULL) ufoFatal("unknown state");
5656 st->LP = ufoPop();
5659 // MTASK:STATE-LBP!
5660 // ( lbp stid -- )
5661 UFWORD(MT_LBP_SET) {
5662 UfoState *st = ufoFindState(ufoPop());
5663 if (st == NULL) ufoFatal("unknown state");
5664 st->LBP = ufoPop();
5667 // MTASK:STATE-DS@
5668 // ( idx stid -- value )
5669 UFWORD(MT_DSTACK_LOAD) {
5670 UfoState *st = ufoFindState(ufoPop());
5671 if (st == NULL) ufoFatal("unknown state");
5672 uint32_t idx = ufoPop();
5673 if (idx >= st->SP) ufoFatal("invalid stack index %u (%u)", idx, st->SP);
5674 ufoPush(st->dStack[st->SP - idx - 1u]);
5677 // MTASK:STATE-RS@
5678 // ( idx stid -- value )
5679 UFWORD(MT_RSTACK_LOAD) {
5680 UfoState *st = ufoFindState(ufoPop());
5681 if (st == NULL) ufoFatal("unknown state");
5682 uint32_t idx = ufoPop();
5683 if (idx >= st->RP - st->RPTop) ufoFatal("invalid stack index %u (%u)", idx, st->RP - st->RPTop);
5684 ufoPush(st->dStack[st->RP - idx - 1u]);
5687 // MTASK:STATE-LS@
5688 // ( idx stid -- value )
5689 UFWORD(MT_LSTACK_LOAD) {
5690 UfoState *st = ufoFindState(ufoPop());
5691 if (st == NULL) ufoFatal("unknown state");
5692 uint32_t idx = ufoPop();
5693 if (idx >= st->LP) ufoFatal("invalid lstack index %u (%u)", idx, st->LP);
5694 ufoPush(st->lStack[st->LP - idx - 1u]);
5697 // MTASK:STATE-DS!
5698 // ( value idx stid -- )
5699 UFWORD(MT_DSTACK_STORE) {
5700 UfoState *st = ufoFindState(ufoPop());
5701 if (st == NULL) ufoFatal("unknown state");
5702 uint32_t idx = ufoPop();
5703 uint32_t value = ufoPop();
5704 if (idx >= st->SP) ufoFatal("invalid stack index %u (%u)", idx, st->SP);
5705 st->dStack[st->SP - idx - 1u] = value;
5708 // MTASK:STATE-RS!
5709 // ( value idx stid -- )
5710 UFWORD(MT_RSTACK_STORE) {
5711 UfoState *st = ufoFindState(ufoPop());
5712 if (st == NULL) ufoFatal("unknown state");
5713 uint32_t idx = ufoPop();
5714 uint32_t value = ufoPop();
5715 if (idx >= st->RP - st->RPTop) ufoFatal("invalid stack index %u (%u)", idx, st->RP - st->RPTop);
5716 st->dStack[st->RP - idx - 1u] = value;
5719 // MTASK:STATE-LS!
5720 // ( value idx stid -- )
5721 UFWORD(MT_LSTACK_STORE) {
5722 UfoState *st = ufoFindState(ufoPop());
5723 if (st == NULL) ufoFatal("unknown state");
5724 uint32_t idx = ufoPop();
5725 uint32_t value = ufoPop();
5726 if (idx >= st->LP) ufoFatal("invalid stack index %u (%u)", idx, st->LP);
5727 st->dStack[st->LP - idx - 1u] = value;
5731 #include "urforth_tty.c"
5734 // ////////////////////////////////////////////////////////////////////////// //
5735 // initial dictionary definitions
5738 #undef UFWORD
5740 #define UFWORD(name_) do { \
5741 const uint32_t xcfa_ = ufoCFAsUsed; \
5742 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5743 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5744 ufoCFAsUsed += 1; \
5745 ufoDefineNative(""#name_, xcfa_, 0); \
5746 } while (0)
5748 #define UFWORDX(strname_,name_) do { \
5749 const uint32_t xcfa_ = ufoCFAsUsed; \
5750 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5751 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5752 ufoCFAsUsed += 1; \
5753 ufoDefineNative(strname_, xcfa_, 0); \
5754 } while (0)
5756 #define UFWORD_IMM(name_) do { \
5757 const uint32_t xcfa_ = ufoCFAsUsed; \
5758 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5759 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5760 ufoCFAsUsed += 1; \
5761 ufoDefineNative(""#name_, xcfa_, 1); \
5762 } while (0)
5764 #define UFWORDX_IMM(strname_,name_) do { \
5765 const uint32_t xcfa_ = ufoCFAsUsed; \
5766 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5767 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5768 ufoCFAsUsed += 1; \
5769 ufoDefineNative(strname_, xcfa_, 1); \
5770 } while (0)
5772 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
5775 //==========================================================================
5777 // ufoFindWordChecked
5779 //==========================================================================
5780 UFO_DISABLE_INLINE uint32_t ufoFindWordChecked (const char *wname) {
5781 const uint32_t cfa = ufoFindWord(wname);
5782 if (cfa == 0) ufoFatal("word '%s' not found", wname);
5783 return cfa;
5787 //==========================================================================
5789 // ufoGetForthVocId
5791 // get "FORTH" vocid
5793 //==========================================================================
5794 uint32_t ufoGetForthVocId (void) {
5795 return ufoForthVocId;
5799 //==========================================================================
5801 // ufoVocSetOnlyDefs
5803 //==========================================================================
5804 void ufoVocSetOnlyDefs (uint32_t vocid) {
5805 ufoImgPutU32(ufoAddrCurrent, vocid);
5806 ufoImgPutU32(ufoAddrContext, vocid);
5810 //==========================================================================
5812 // ufoCreateVoc
5814 // return voc PFA (vocid)
5816 //==========================================================================
5817 uint32_t ufoCreateVoc (const char *wname, uint32_t parentvocid, uint32_t flags) {
5818 // create wordlist struct
5819 // typeid, used by Forth code (structs and such)
5820 ufoImgEmitU32(0); // typeid
5821 // vocid points here, to "LATEST-LFA"
5822 const uint32_t vocid = UFO_GET_DP();
5823 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
5824 ufoImgEmitU32(0); // latest
5825 const uint32_t vlink = UFO_GET_DP();
5826 if ((vocid & UFO_ADDR_TEMP_BIT) == 0) {
5827 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink)); // voclink
5828 ufoImgPutU32(ufoAddrVocLink, vlink); // update voclink
5829 } else {
5830 abort();
5831 ufoImgEmitU32(0);
5833 ufoImgEmitU32(parentvocid); // parent
5834 const uint32_t hdraddr = UFO_GET_DP();
5835 ufoImgEmitU32(0); // word header
5836 // create empty hash table
5837 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) ufoImgEmitU32(0);
5838 // update CONTEXT and CURRENT if this is the first wordlist ever
5839 if (ufoImgGetU32(ufoAddrContext) == 0) {
5840 ufoImgPutU32(ufoAddrContext, vocid);
5842 if (ufoImgGetU32(ufoAddrCurrent) == 0) {
5843 ufoImgPutU32(ufoAddrCurrent, vocid);
5845 // create word header
5846 if (wname != NULL && wname[0] != 0) {
5848 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5849 flags &=
5850 //UFW_FLAG_IMMEDIATE|
5851 //UFW_FLAG_SMUDGE|
5852 //UFW_FLAG_NORETURN|
5853 UFW_FLAG_HIDDEN|
5854 //UFW_FLAG_CBLOCK|
5855 //UFW_FLAG_VOCAB|
5856 //UFW_FLAG_SCOLON|
5857 UFW_FLAG_PROTECTED;
5858 flags |= UFW_FLAG_VOCAB;
5860 flags &= 0xffffff00u;
5861 flags |= UFW_FLAG_VOCAB;
5862 ufoCreateWordHeader(wname, flags);
5863 const uint32_t cfa = UFO_GET_DP();
5864 ufoImgEmitU32(ufoDoVocCFA); // cfa
5865 ufoImgEmitU32(vocid); // pfa
5866 // update vocab header pointer
5867 const uint32_t lfa = UFO_CFA_TO_LFA(cfa);
5868 ufoImgPutU32(hdraddr, UFO_LFA_TO_NFA(lfa));
5869 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5870 ufoDumpWordHeader(lfa);
5871 #endif
5873 return vocid;
5877 //==========================================================================
5879 // ufoSetLatestArgs
5881 //==========================================================================
5882 static void ufoSetLatestArgs (uint32_t warg) {
5883 const uint32_t curr = ufoImgGetU32(ufoAddrCurrent);
5884 const uint32_t lfa = ufoImgGetU32(curr);
5885 const uint32_t nfa = UFO_LFA_TO_NFA(lfa);
5886 uint32_t flags = ufoImgGetU32(nfa);
5887 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
5888 flags &= ~UFW_WARG_MASK;
5889 flags |= warg & UFW_WARG_MASK;
5890 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
5891 ufoImgPutU32(nfa, flags);
5892 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5893 ufoDumpWordHeader(lfa);
5894 #endif
5898 //==========================================================================
5900 // ufoDefine
5902 //==========================================================================
5903 static void ufoDefineNative (const char *wname, uint32_t cfaidx, int immed) {
5904 cfaidx |= UFO_ADDR_CFA_BIT;
5905 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5906 flags &=
5907 //UFW_FLAG_IMMEDIATE|
5908 //UFW_FLAG_SMUDGE|
5909 //UFW_FLAG_NORETURN|
5910 UFW_FLAG_HIDDEN|
5911 //UFW_FLAG_CBLOCK|
5912 //UFW_FLAG_VOCAB|
5913 //UFW_FLAG_SCOLON|
5914 UFW_FLAG_PROTECTED;
5915 if (immed) flags |= UFW_FLAG_IMMEDIATE;
5916 ufoCreateWordHeader(wname, flags);
5917 ufoImgEmitU32(cfaidx);
5921 //==========================================================================
5923 // ufoDefineConstant
5925 //==========================================================================
5926 static void ufoDefineConstant (const char *name, uint32_t value) {
5927 ufoDefineNative(name, ufoDoConstCFA, 0);
5928 ufoImgEmitU32(value);
5932 //==========================================================================
5934 // ufoDefineUserVar
5936 //==========================================================================
5937 static void ufoDefineUserVar (const char *name, uint32_t addr) {
5938 ufoDefineNative(name, ufoDoUserVariableCFA, 0);
5939 ufoImgEmitU32(addr);
5943 //==========================================================================
5945 // ufoDefineVar
5947 //==========================================================================
5949 static void ufoDefineVar (const char *name, uint32_t value) {
5950 ufoDefineNative(name, ufoDoVarCFA, 0);
5951 ufoImgEmitU32(value);
5956 //==========================================================================
5958 // ufoDefineDefer
5960 //==========================================================================
5961 static void ufoDefineDefer (const char *name, uint32_t value) {
5962 ufoDefineNative(name, ufoDoDeferCFA, 0);
5963 ufoImgEmitU32(value);
5967 //==========================================================================
5969 // ufoHiddenWords
5971 //==========================================================================
5972 static void ufoHiddenWords (void) {
5973 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5974 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
5978 //==========================================================================
5980 // ufoPublicWords
5982 //==========================================================================
5983 static void ufoPublicWords (void) {
5984 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5985 ufoImgPutU32(ufoAddrNewWordFlags, flags & ~UFW_FLAG_HIDDEN);
5989 //==========================================================================
5991 // ufoDefineForth
5993 //==========================================================================
5994 static void ufoDefineForth (const char *name) {
5995 ufoDefineNative(name, ufoDoForthCFA, 0);
5999 //==========================================================================
6001 // ufoDefineForthImm
6003 //==========================================================================
6004 static void ufoDefineForthImm (const char *name) {
6005 ufoDefineNative(name, ufoDoForthCFA, 1);
6009 //==========================================================================
6011 // ufoDefineForthHidden
6013 //==========================================================================
6014 static void ufoDefineForthHidden (const char *name) {
6015 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6016 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6017 ufoDefineNative(name, ufoDoForthCFA, 0);
6018 ufoImgPutU32(ufoAddrNewWordFlags, flags);
6022 //==========================================================================
6024 // ufoDefineSColonForth
6026 // create word suitable for scattered colon extension
6028 //==========================================================================
6029 static void ufoDefineSColonForth (const char *name) {
6030 ufoDefineNative(name, ufoDoForthCFA, 0);
6031 // placeholder for scattered colon
6032 // it will compile two branches:
6033 // the first branch will jump to the first "..:" word (or over the two branches)
6034 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
6035 // this way, each extension word will simply fix the last branch address, and update list tail
6036 // at the creation time, second branch points to the first branch
6037 UFC("FORTH:(BRANCH)");
6038 const uint32_t xjmp = UFO_GET_DP();
6039 ufoImgEmitU32(0);
6040 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp);
6041 ufoImgPutU32(xjmp, UFO_GET_DP());
6045 //==========================================================================
6047 // ufoDoneForth
6049 //==========================================================================
6050 UFO_FORCE_INLINE void ufoDoneForth (void) {
6051 UFC("FORTH:(EXIT)");
6055 //==========================================================================
6057 // ufoNewState
6059 // create a new state, its execution will start from the given CFA.
6060 // state is not automatically activated.
6062 //==========================================================================
6063 static UfoState *ufoNewState (uint32_t cfa) {
6064 // find free state id
6065 uint32_t fidx = 0;
6066 uint32_t bmp = ufoStateUsedBitmap[0];
6067 while (fidx != (uint32_t)(UFO_MAX_STATES/32) && bmp == ~(uint32_t)0) {
6068 fidx += 1u;
6069 bmp = ufoStateUsedBitmap[fidx];
6071 if (fidx == (uint32_t)(UFO_MAX_STATES/32)) ufoFatal("too many execution states");
6072 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6073 fidx *= 32u;
6074 while ((bmp & 0x01) != 0) { fidx += 1u; bmp >>= 1; }
6075 ufo_assert(fidx < UFO_MAX_STATES);
6076 ufo_assert((ufoStateUsedBitmap[fidx / 32u] & ((uint32_t)1 << (fidx & 0x1f))) == 0);
6077 ufo_assert(ufoStateMap[fidx] == NULL);
6078 UfoState *st = calloc(1, sizeof(UfoState));
6079 if (st == NULL) ufoFatal("out of memory for states");
6080 st->id = fidx + 1u;
6081 st->vmRPopCFA = 1;
6082 st->rStack[0] = 0xdeadf00d; // dummy value
6083 st->rStack[1] = cfa;
6084 st->RP = 2;
6085 ufoStateMap[fidx] = st;
6086 ufoStateUsedBitmap[fidx / 32u] |= ((uint32_t)1 << (fidx & 0x1f));
6087 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6088 return st;
6092 //==========================================================================
6094 // ufoFreeState
6096 // free all memory used for the state, remove it from state list.
6097 // WARNING! never free current state!
6099 //==========================================================================
6100 static void ufoFreeState (UfoState *st) {
6101 if (st != NULL) {
6102 if (st == ufoCurrState) ufoFatal("cannot free active state");
6103 if (ufoYieldedState == st) ufoYieldedState = NULL;
6104 if (ufoDebuggerState == st) ufoDebuggerState = NULL;
6105 const uint32_t fidx = st->id - 1u;
6106 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6107 ufo_assert(fidx < UFO_MAX_STATES);
6108 ufo_assert((ufoStateUsedBitmap[fidx / 32u] & (1u << (fidx & 0x1f))) != 0);
6109 ufo_assert(ufoStateMap[fidx] == st);
6110 // free default TIB handle
6111 UfoState *oldst = ufoCurrState;
6112 ufoCurrState = st;
6113 const uint32_t tib = ufoImgGetU32(ufoAddrDefTIB);
6114 if ((tib & UFO_ADDR_TEMP_BIT) != 0) {
6115 UfoHandle *tibh = ufoGetHandle(tib);
6116 if (tibh != NULL) ufoFreeHandle(tibh);
6118 ufoCurrState = oldst;
6119 // free temp buffer
6120 if (st->imageTemp != NULL) free(st->imageTemp);
6121 free(st);
6122 ufoStateMap[fidx] = NULL;
6123 ufoStateUsedBitmap[fidx / 32u] &= ~((uint32_t)1 << (fidx & 0x1f));
6128 //==========================================================================
6130 // ufoFindState
6132 //==========================================================================
6133 static UfoState *ufoFindState (uint32_t stid) {
6134 UfoState *res = NULL;
6135 if (stid != 0 && stid <= UFO_MAX_STATES) {
6136 stid -= 1u;
6137 res = ufoStateMap[stid];
6138 if (res != NULL) {
6139 ufo_assert((ufoStateUsedBitmap[stid / 32u] & (1u << (stid & 0x1f))) != 0);
6140 ufo_assert(res->id == stid + 1u);
6141 } else {
6142 ufo_assert((ufoStateUsedBitmap[stid / 32u] & (1u << (stid & 0x1f))) == 0);
6145 return res;
6149 //==========================================================================
6151 // ufoSwitchToState
6153 //==========================================================================
6154 static void ufoSwitchToState (UfoState *newst) {
6155 ufo_assert(newst != NULL);
6156 if (newst != ufoCurrState) {
6157 ufoCurrState = newst;
6163 //==========================================================================
6165 // ufoReset
6167 //==========================================================================
6168 UFO_DISABLE_INLINE void ufoReset (void) {
6169 if (ufoCurrState == NULL) ufoFatal("no active execution state");
6171 ufoSP = 0; ufoRP = 0;
6172 ufoLP = 0; ufoLBP = 0;
6174 ufoInRunWord = 0;
6175 ufoVMStop = 0; ufoVMAbort = 0;
6177 ufoInBacktrace = 0;
6179 ufoInitStateUserVars(ufoCurrState, 0);
6180 ufoImgPutU32(ufoAddrSTATE, 0);
6181 ufoImgPutU32(ufoAddrRedefineWarning, UFO_REDEF_WARN_NORMAL);
6182 ufoResetTib();
6184 ufoImgPutU32(ufoAddrDPTemp, 0);
6186 ufoImgPutU32(ufoAddrNewWordFlags, 0);
6187 ufoVocSetOnlyDefs(ufoForthVocId);
6191 //==========================================================================
6193 // ufoCompileStrLit
6195 // compile string literal, the same as QUOTE_IMM
6197 //==========================================================================
6198 static void ufoCompileStrLit (const char *str) {
6199 if (str == NULL) str = "";
6200 const size_t slen = strlen(str);
6201 if (slen > 255) ufoFatal("string literal too long");
6202 UFC("FORTH:(STRLIT8)");
6203 ufoImgEmitU8((uint8_t)slen);
6204 for (size_t f = 0; f < slen; f += 1) {
6205 ufoImgEmitU8(((const unsigned char *)str)[f]);
6207 ufoImgEmitU8(0);
6208 ufoImgEmitAlign();
6212 //==========================================================================
6214 // ufoCompileLit
6216 //==========================================================================
6217 static __attribute__((unused)) void ufoCompileLit (uint32_t value) {
6218 UFC("FORTH:(LIT)");
6219 ufoImgEmitU32(value);
6223 //==========================================================================
6225 // ufoMarkFwd
6227 //==========================================================================
6228 UFO_FORCE_INLINE uint32_t ufoMarkFwd (void) {
6229 const uint32_t res = UFO_GET_DP();
6230 ufoImgEmitU32(0);
6231 return res;
6235 //==========================================================================
6237 // ufoResolveFwd
6239 //==========================================================================
6240 UFO_FORCE_INLINE void ufoResolveFwd (uint32_t jaddr) {
6241 ufoImgPutU32(jaddr, UFO_GET_DP());
6245 //==========================================================================
6247 // ufoMarkBwd
6249 //==========================================================================
6250 UFO_FORCE_INLINE uint32_t ufoMarkBwd (void) {
6251 return UFO_GET_DP();
6255 //==========================================================================
6257 // ufoResolveBwd
6259 //==========================================================================
6260 UFO_FORCE_INLINE void ufoResolveBwd (uint32_t jaddr) {
6261 ufoImgEmitU32(jaddr);
6265 //==========================================================================
6267 // ufoDefineEmitType
6269 //==========================================================================
6270 UFO_DISABLE_INLINE void ufoDefineEmitType (void) {
6271 // ( ch -- )
6272 ufoDefineForth("EMIT");
6273 UFC("(NORM-EMIT-CHAR)");
6274 UFC("(EMIT)");
6275 ufoDoneForth();
6277 // ( ch -- )
6278 ufoDefineForth("XEMIT");
6279 UFC("(NORM-XEMIT-CHAR)");
6280 UFC("(EMIT)");
6281 ufoDoneForth();
6283 // ( -- )
6284 ufoDefineForth("CR");
6285 UFC("NL"); UFC("(EMIT)");
6286 ufoDoneForth();
6288 // ( -- )
6289 ufoDefineForth("SPACE");
6290 UFC("BL"); UFC("(EMIT)");
6291 ufoDoneForth();
6293 // ( count -- )
6294 ufoDefineForth("SPACES");
6295 const uint32_t spaces_again = ufoMarkBwd();
6296 UFC("DUP"); ufoCompileLit(0); UFC(">");
6297 UFC("FORTH:(0BRANCH)"); const uint32_t spaces_exit = ufoMarkFwd();
6298 UFC("SPACE"); ufoCompileLit(1); UFC("-");
6299 UFC("FORTH:(BRANCH)"); ufoResolveBwd(spaces_again);
6300 ufoResolveFwd(spaces_exit);
6301 UFC("DROP");
6302 ufoDoneForth();
6304 // ( -- )
6305 ufoDefineForth("ENDCR");
6306 UFC("LASTCR?");
6307 UFC("FORTH:(TBRANCH)"); const uint32_t endcr_exit = ufoMarkFwd();
6308 UFC("CR");
6309 ufoResolveFwd(endcr_exit);
6310 ufoDoneForth();
6312 // ( addr count -- )
6313 ufoDefineForth("TYPE");
6314 UFC("A>R"); UFC("SWAP"); UFC(">A");
6315 const uint32_t type_again = ufoMarkBwd();
6316 UFC("DUP"); ufoCompileLit(0); UFC(">");
6317 UFC("FORTH:(0BRANCH)"); const uint32_t type_exit = ufoMarkFwd();
6318 ufoCompileLit(0); UFC("C@A+"); UFC("EMIT"); UFC("+1>A");
6319 ufoCompileLit(1); UFC("-");
6320 UFC("FORTH:(BRANCH)"); ufoResolveBwd(type_again);
6321 ufoResolveFwd(type_exit);
6322 UFC("DROP"); UFC("R>A");
6323 ufoDoneForth();
6325 // ( addr count -- )
6326 ufoDefineForth("XTYPE");
6327 UFC("A>R"); UFC("SWAP"); UFC(">A");
6328 const uint32_t xtype_again = ufoMarkBwd();
6329 UFC("DUP"); ufoCompileLit(0); UFC(">");
6330 UFC("FORTH:(0BRANCH)"); const uint32_t xtype_exit = ufoMarkFwd();
6331 ufoCompileLit(0); UFC("C@A+"); UFC("XEMIT"); UFC("+1>A");
6332 ufoCompileLit(1); UFC("-");
6333 UFC("FORTH:(BRANCH)"); ufoResolveBwd(xtype_again);
6334 ufoResolveFwd(xtype_exit);
6335 UFC("DROP"); UFC("R>A");
6336 ufoDoneForth();
6340 //==========================================================================
6342 // ufoDefineInterpret
6344 // define "INTERPRET" in Forth
6346 //==========================================================================
6347 UFO_DISABLE_INLINE void ufoDefineInterpret (void) {
6348 // skip comments, parse name, refilling lines if necessary
6349 ufoDefineForthHidden("(INTERPRET-PARSE-NAME)");
6350 const uint32_t label_ipn_again = ufoMarkBwd();
6351 UFC("TRUE"); UFC("(PARSE-SKIP-COMMENTS)");
6352 UFC("PARSE-NAME");
6353 UFC("DUP");
6354 UFC("FORTH:(TBRANCH)"); const uint32_t label_ipn_exit_fwd = ufoMarkFwd();
6355 UFC("2DROP");
6356 UFC("REFILL");
6357 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_ipn_again);
6358 // refill failed
6359 UFC("FORTH:STATE"); UFC("@");
6360 ufoCompileStrLit("unexpected end of file"); UFC("?ERROR");
6361 UFC("FORTH:(UFO-INTERPRET-FINISHED)");
6362 // patch the jump above
6363 ufoResolveFwd(label_ipn_exit_fwd);
6364 ufoDoneForth();
6365 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
6367 ufoDefineForth("INTERPRET");
6368 const uint32_t label_it_again = ufoMarkBwd();
6369 UFC("FORTH:(INTERPRET-PARSE-NAME)");
6370 // try defered checker
6371 // ( addr count FALSE -- addr count FALSE / TRUE )
6372 UFC("FALSE"); UFC("(INTERPRET-CHECK-WORD)");
6373 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again);
6374 UFC("2DUP"); UFC("FIND-WORD"); // ( addr count cfa TRUE / addr count FALSE )
6375 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_try_num = ufoMarkFwd();
6376 UFC("NROT"); UFC("2DROP"); // drop word string
6377 UFC("STATE"); UFC("@");
6378 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_exec_fwd = ufoMarkFwd();
6379 // compiling; check immediate bit
6380 UFC("DUP"); UFC("CFA->NFA"); UFC("@");
6381 UFC("COMPILER:(WFLAG-IMMEDIATE)"); UFC("AND");
6382 UFC("FORTH:(TBRANCH)"); const uint32_t label_it_exec_imm = ufoMarkFwd();
6383 // compile it
6384 UFC("FORTH:COMPILE,");
6385 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again);
6386 // execute it
6387 ufoResolveFwd(label_it_exec_imm);
6388 ufoResolveFwd(label_it_exec_fwd);
6389 UFC("EXECUTE");
6390 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again);
6391 // not a word, try a number
6392 ufoResolveFwd(label_it_try_num);
6393 UFC("2DUP"); UFC("TRUE"); UFC("BASE"); UFC("@"); UFC("(BASED-NUMBER)");
6394 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
6395 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_num_error = ufoMarkFwd();
6396 // number
6397 UFC("NROT"); UFC("2DROP"); // drop word string
6398 // do we need to compile it?
6399 UFC("STATE"); UFC("@");
6400 UFC("FORTH:(0BRANCH)"); ufoResolveBwd(label_it_again);
6401 // compile "(LITERAL)" (do it properly, with "LITCFA")
6402 UFC("FORTH:(LITCFA)"); UFC("FORTH:(LIT)");
6403 UFC("FORTH:COMPILE,"); // compile "(LIT)" CFA
6404 UFC("FORTH:,"); // compile number
6405 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again);
6406 // error
6407 ufoResolveFwd(label_it_num_error);
6408 // ( addr count FALSE -- addr count FALSE / TRUE )
6409 UFC("FALSE"); UFC("(INTERPRET-WORD-NOT-FOUND)");
6410 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again);
6411 UFC("ENDCR"); UFC("SPACE"); UFC("XTYPE");
6412 ufoCompileStrLit(" -- wut?\n"); UFC("TYPE");
6413 ufoCompileStrLit("unknown word");
6414 UFC("ERROR");
6415 ufoDoneForth();
6416 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
6420 //==========================================================================
6422 // ufoInitBaseDict
6424 //==========================================================================
6425 UFO_DISABLE_INLINE void ufoInitBaseDict (void) {
6426 uint32_t imgAddr = 0;
6428 // reserve 64 bytes for nothing
6429 for (uint32_t f = 0; f < 64; f += 1) {
6430 ufoImgPutU8(imgAddr, 0);
6431 imgAddr += 1;
6433 // align
6434 while ((imgAddr & 3) != 0) {
6435 ufoImgPutU8(imgAddr, 0);
6436 imgAddr += 1;
6439 // STATE
6440 ufoAddrSTATE = imgAddr;
6441 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6443 // DP
6444 ufoAddrDP = imgAddr;
6445 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6447 // DP-TEMP
6448 ufoAddrDPTemp = imgAddr;
6449 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6451 // CONTEXT
6452 ufoAddrContext = imgAddr;
6453 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6455 // CURRENT
6456 ufoAddrCurrent = imgAddr;
6457 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6459 // (LATEST-XFA)
6460 ufoAddrLastXFA = imgAddr;
6461 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6463 // (VOC-LINK)
6464 ufoAddrVocLink = imgAddr;
6465 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
6467 // (NEW-WORD-FLAGS)
6468 ufoAddrNewWordFlags = imgAddr;
6469 ufoImgPutU32(imgAddr, UFW_FLAG_PROTECTED); imgAddr += 4u;
6471 // WORD-REDEFINE-WARN-MODE
6472 ufoAddrRedefineWarning = imgAddr;
6473 ufoImgPutU32(imgAddr, UFO_REDEF_WARN_NORMAL); imgAddr += 4u;
6475 ufoImgPutU32(ufoAddrDP, imgAddr);
6476 ufoImgPutU32(ufoAddrDPTemp, 0);
6478 #if 0
6479 fprintf(stderr, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr, UFO_GET_DP());
6480 #endif
6484 //==========================================================================
6486 // ufoInitStateUserVars
6488 //==========================================================================
6489 static void ufoInitStateUserVars (UfoState *st, int initial) {
6490 ufo_assert(st != NULL);
6491 if (st->imageTempSize < 8192u) {
6492 uint32_t *itmp = realloc(st->imageTemp, 8192);
6493 if (itmp == NULL) ufoFatal("out of memory for state user area");
6494 st->imageTemp = itmp;
6495 memset((uint8_t *)st->imageTemp + st->imageTempSize, 0, 8192u - st->imageTempSize);
6496 st->imageTempSize = 8192;
6498 st->imageTemp[(ufoAddrBASE & UFO_ADDR_TEMP_MASK) / 4u] = 10;
6499 if (initial) {
6500 st->imageTemp[(ufoAddrUserVarUsed & UFO_ADDR_TEMP_MASK) / 4u] = ufoAddrUserVarUsed;
6501 st->imageTemp[(ufoAddrDefTIB & UFO_ADDR_TEMP_MASK) / 4u] = UFO_DEF_TIB_ADDR;
6502 st->imageTemp[(ufoAddrTIBx & UFO_ADDR_TEMP_MASK) / 4u] = UFO_DEF_TIB_ADDR;
6503 } else {
6504 st->imageTemp[(ufoAddrTIBx & UFO_ADDR_TEMP_MASK) / 4u] =
6505 st->imageTemp[(ufoAddrDefTIB & UFO_ADDR_TEMP_MASK) / 4u];
6507 st->imageTemp[(ufoAddrINx & UFO_ADDR_TEMP_MASK) / 4u] = 0;
6511 //==========================================================================
6513 // ufoInitBasicWords
6515 //==========================================================================
6516 UFO_DISABLE_INLINE void ufoInitBasicWords (void) {
6517 ufoDefineConstant("FALSE", 0);
6518 ufoDefineConstant("TRUE", ufoTrueValue);
6520 ufoDefineConstant("BL", 32);
6521 ufoDefineConstant("NL", 10);
6523 // user variables
6524 ufoDefineUserVar("BASE", ufoAddrBASE);
6525 ufoDefineUserVar("TIB", ufoAddrTIBx);
6526 ufoDefineUserVar(">IN", ufoAddrINx);
6527 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB);
6528 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed);
6529 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT);
6530 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE);
6531 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR);
6532 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK);
6534 ufoDefineUserVar("STATE", ufoAddrSTATE);
6535 ufoDefineConstant("CONTEXT", ufoAddrContext);
6536 ufoDefineConstant("CURRENT", ufoAddrCurrent);
6538 ufoHiddenWords();
6539 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA);
6540 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink);
6541 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags);
6542 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT);
6543 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT);
6544 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT);
6545 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK);
6547 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR);
6548 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR + 4u); // reserve room for counter
6549 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE - 8u);
6551 ufoDefineConstant("(DP)", ufoAddrDP);
6552 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp);
6553 ufoPublicWords();
6555 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
6556 UFWORDX("SP0!", SP0_STORE);
6557 UFWORDX("RP0!", RP0_STORE);
6559 UFWORDX("PAD", PAD);
6561 UFWORDX("@", PEEK);
6562 UFWORDX("C@", CPEEK);
6563 UFWORDX("W@", WPEEK);
6565 UFWORDX("!", POKE);
6566 UFWORDX("C!", CPOKE);
6567 UFWORDX("W!", WPOKE);
6569 UFWORDX(",", COMMA);
6570 UFWORDX("C,", CCOMMA);
6571 UFWORDX("W,", WCOMMA);
6573 UFWORDX("A>", REGA_LOAD);
6574 UFWORDX(">A", REGA_STORE);
6575 UFWORDX("A-SWAP", REGA_SWAP);
6576 UFWORDX("+1>A", REGA_INC);
6577 UFWORDX("A>R", REGA_TO_R);
6578 UFWORDX("R>A", R_TO_REGA);
6580 UFWORDX("@A+", PEEK_REGA_IDX);
6581 UFWORDX("C@A+", CPEEK_REGA_IDX);
6582 UFWORDX("W@A+", WPEEK_REGA_IDX);
6584 UFWORDX("!A+", POKE_REGA_IDX);
6585 UFWORDX("C!A+", CPOKE_REGA_IDX);
6586 UFWORDX("W!A+", WPOKE_REGA_IDX);
6588 ufoHiddenWords();
6589 UFWORDX("(LIT)", PAR_LIT); ufoSetLatestArgs(UFW_WARG_LIT);
6590 UFWORDX("(LITCFA)", PAR_LITCFA); ufoSetLatestArgs(UFW_WARG_CFA);
6591 UFWORDX("(LITVOCID)", PAR_LITVOCID); ufoSetLatestArgs(UFW_WARG_VOCID);
6592 UFWORDX("(STRLIT8)", PAR_STRLIT8); ufoSetLatestArgs(UFW_WARG_C1STRZ);
6593 UFWORDX("(EXIT)", PAR_EXIT);
6595 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION);
6596 ufoDefineDefer("(UFO-INTERPRET-FINISHED)", ufoFindWordChecked("FORTH:(UFO-INTERPRET-FINISHED-ACTION)"));
6598 ufoStrLit8CFA = ufoFindWordChecked("FORTH:(STRLIT8)");
6600 UFWORDX("(L-ENTER)", PAR_LENTER); ufoSetLatestArgs(UFW_WARG_LIT);
6601 UFWORDX("(L-LEAVE)", PAR_LLEAVE);
6602 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD);
6603 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE);
6605 UFWORDX("(BRANCH)", PAR_BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
6606 UFWORDX("(TBRANCH)", PAR_TBRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
6607 UFWORDX("(0BRANCH)", PAR_0BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
6608 ufoPublicWords();
6610 UFWORDX("GET-MSECS", GET_MSECS);
6614 //==========================================================================
6616 // ufoInitBasicCompilerWords
6618 //==========================================================================
6619 UFO_DISABLE_INLINE void ufoInitBasicCompilerWords (void) {
6620 // create "COMPILER" vocabulary
6621 ufoCompilerVocId = ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED);
6622 ufoVocSetOnlyDefs(ufoCompilerVocId);
6624 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA);
6625 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA);
6626 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA);
6627 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA);
6628 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA);
6629 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA);
6630 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA);
6631 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA);
6633 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE);
6634 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE);
6635 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN);
6636 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN);
6637 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK);
6638 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB);
6639 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON);
6640 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED);
6642 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK);
6643 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE);
6644 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH);
6645 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT);
6646 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ);
6647 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA);
6648 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK);
6649 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID);
6650 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ);
6652 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST);
6653 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK);
6654 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT);
6655 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER);
6656 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE);
6657 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE);
6658 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG);
6660 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE);
6661 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE);
6662 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL);
6664 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning);
6666 UFWORDX("(UNESCAPE)", PAR_UNESCAPE);
6668 UFWORDX("?EXEC", QEXEC);
6669 UFWORDX("?COMP", QCOMP);
6671 // interpreter
6673 UFWORDX("(INTERPRET-DUMB)", PAR_INTERPRET_DUMB); UFCALL(PAR_HIDDEN);
6674 const uint32_t idumbCFA = UFO_LFA_TO_CFA(ufoImgGetU32(ufoImgGetU32(ufoAddrCurrent)));
6675 ufo_assert(idumbCFA == UFO_PFA_TO_CFA(UFO_GET_DP()));
6678 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER);
6679 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER);
6681 ufoVocSetOnlyDefs(ufoForthVocId);
6685 //==========================================================================
6687 // ufoInitMoreWords
6689 //==========================================================================
6690 UFO_DISABLE_INLINE void ufoInitMoreWords (void) {
6691 UFWORDX("COMPILE,", COMMA); // just an alias, for clarity
6693 UFWORDX("CFA->PFA", CFA2PFA);
6694 UFWORDX("PFA->CFA", PFA2CFA);
6695 UFWORDX("CFA->NFA", CFA2NFA);
6696 UFWORDX("NFA->CFA", NFA2CFA);
6697 UFWORDX("CFA->LFA", CFA2LFA);
6698 UFWORDX("LFA->CFA", LFA2CFA);
6699 UFWORDX("LFA->PFA", LFA2PFA);
6700 UFWORDX("LFA->BFA", LFA2BFA);
6701 UFWORDX("LFA->XFA", LFA2XFA);
6702 UFWORDX("LFA->YFA", LFA2YFA);
6703 UFWORDX("LFA->NFA", LFA2NFA);
6704 UFWORDX("NFA->LFA", NFA2LFA);
6705 UFWORDX("CFA->WEND", CFA2WEND);
6707 UFWORDX("ERROR", ERROR);
6708 UFWORDX("?ERROR", QERROR);
6710 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER);
6711 UFWORDX("FIND-WORD", FIND_WORD);
6712 UFWORDX("FIND-WORD-IN-VOC", FIND_WORD_IN_VOC);
6713 UFWORDX("FIND-WORD-IN-VOC-AND-PARENTS", FIND_WORD_IN_VOC_AND_PARENTS);
6715 UFWORDX_IMM("\"", QUOTE_IMM);
6717 UFWORD(EXECUTE);
6718 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL);
6720 UFWORD(DUP);
6721 UFWORDX("?DUP", QDUP);
6722 UFWORDX("2DUP", DDUP);
6723 UFWORD(DROP);
6724 UFWORDX("2DROP", DDROP);
6725 UFWORD(SWAP);
6726 UFWORDX("2SWAP", DSWAP);
6727 UFWORD(OVER);
6728 UFWORDX("2OVER", DOVER);
6729 UFWORD(ROT);
6730 UFWORD(NROT);
6731 UFWORDX("PICK", PICK);
6732 UFWORDX("ROLL", ROLL);
6734 UFWORD(RDUP);
6735 UFWORD(RDROP);
6736 UFWORDX(">R", DTOR);
6737 UFWORDX("R>", RTOD);
6738 UFWORDX("R@", RPEEK);
6739 UFWORDX("RPICK", RPICK);
6740 UFWORDX("RROLL", RROLL);
6741 UFWORDX("RSWAP", RSWAP);
6742 UFWORDX("ROVER", ROVER);
6743 UFWORDX("RROT", RROT);
6744 UFWORDX("RNROT", RNROT);
6746 UFWORDX("FLUSH-EMIT", FLUSH_EMIT);
6747 UFWORDX("(EMIT)", PAR_EMIT);
6748 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR);
6749 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR);
6750 UFWORDX("LASTCR?", LASTCRQ);
6751 UFWORDX("LASTCR!", LASTCRSET);
6753 // simple math
6754 UFWORDX("+", PLUS);
6755 UFWORDX("-", MINUS);
6756 UFWORDX("*", MUL);
6757 UFWORDX("U*", UMUL);
6758 UFWORDX("/", DIV);
6759 UFWORDX("U/", UDIV);
6760 UFWORDX("MOD", MOD);
6761 UFWORDX("UMOD", UMOD);
6762 UFWORDX("/MOD", DIVMOD);
6763 UFWORDX("U/MOD", UDIVMOD);
6764 UFWORDX("*/", MULDIV);
6765 UFWORDX("U*/", UMULDIV);
6766 UFWORDX("*/MOD", MULDIVMOD);
6767 UFWORDX("U*/MOD", UMULDIVMOD);
6768 UFWORDX("M*", MMUL);
6769 UFWORDX("UM*", UMMUL);
6770 UFWORDX("M/MOD", MDIVMOD);
6771 UFWORDX("UM/MOD", UMDIVMOD);
6772 UFWORDX("UDS*", UDSMUL);
6774 UFWORDX("SM/REM", SMREM);
6775 UFWORDX("FM/MOD", FMMOD);
6777 UFWORDX("D-", DMINUS);
6778 UFWORDX("D+", DPLUS);
6779 UFWORDX("D=", DEQU);
6780 UFWORDX("D<", DLESS);
6781 UFWORDX("D<=", DLESSEQU);
6782 UFWORDX("DU<", DULESS);
6783 UFWORDX("DU<=", DULESSEQU);
6785 UFWORDX("2U*", ONESHL);
6786 UFWORDX("2U/", ONESHR);
6787 UFWORDX("4U*", TWOSHL);
6788 UFWORDX("4U/", TWOSHR);
6790 UFWORD(ASH);
6791 UFWORD(LSH);
6793 // logic
6794 UFWORDX("<", LESS);
6795 UFWORDX(">", GREAT);
6796 UFWORDX("<=", LESSEQU);
6797 UFWORDX(">=", GREATEQU);
6798 UFWORDX("U<", ULESS);
6799 UFWORDX("U>", UGREAT);
6800 UFWORDX("U<=", ULESSEQU);
6801 UFWORDX("U>=", UGREATEQU);
6802 UFWORDX("=", EQU);
6803 UFWORDX("<>", NOTEQU);
6805 UFWORD(NOT);
6806 UFWORD(BITNOT);
6807 UFWORD(AND);
6808 UFWORD(OR);
6809 UFWORD(XOR);
6810 UFWORDX("LOGAND", LOGAND);
6811 UFWORDX("LOGOR", LOGOR);
6813 // TIB and parser
6814 UFWORDX("(TIB-IN)", TIB_IN);
6815 UFWORDX("TIB-PEEKCH", TIB_PEEKCH);
6816 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS);
6817 UFWORDX("TIB-GETCH", TIB_GETCH);
6818 UFWORDX("TIB-SKIPCH", TIB_SKIPCH);
6820 UFWORDX("REFILL", REFILL);
6821 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS);
6823 ufoHiddenWords();
6824 UFWORDX("(PARSE)", PAR_PARSE);
6825 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS);
6826 ufoPublicWords();
6827 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS);
6828 UFWORDX("PARSE-NAME", PARSE_NAME);
6829 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE);
6830 UFWORDX("PARSE", PARSE);
6832 UFWORDX_IMM("[", LBRACKET_IMM);
6833 UFWORDX("]", RBRACKET);
6835 ufoHiddenWords();
6836 UFWORDX("(VSP@)", PAR_GET_VSP);
6837 UFWORDX("(VSP!)", PAR_SET_VSP);
6838 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD);
6839 UFWORDX("(VSP-AT!)", PAR_VSP_STORE);
6840 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE);
6842 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE);
6843 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE);
6844 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE);
6845 ufoPublicWords();
6849 //==========================================================================
6851 // ufoInitHandleWords
6853 //==========================================================================
6854 UFO_DISABLE_INLINE void ufoInitHandleWords (void) {
6855 // create "HANDLE" vocabulary
6856 const uint32_t handleVocId = ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED);
6857 ufoVocSetOnlyDefs(handleVocId);
6858 UFWORDX("NEW", PAR_NEW_HANDLE);
6859 UFWORDX("FREE", PAR_FREE_HANDLE);
6860 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID);
6861 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID);
6862 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE);
6863 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE);
6864 UFWORDX("USED@", PAR_HANDLE_GET_USED);
6865 UFWORDX("USED!", PAR_HANDLE_SET_USED);
6866 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE);
6867 UFWORDX("W@", PAR_HANDLE_LOAD_WORD);
6868 UFWORDX("@", PAR_HANDLE_LOAD_CELL);
6869 UFWORDX("C!", PAR_HANDLE_STORE_BYTE);
6870 UFWORDX("W!", PAR_HANDLE_STORE_WORD);
6871 UFWORDX("!", PAR_HANDLE_STORE_CELL);
6872 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE);
6873 ufoVocSetOnlyDefs(ufoForthVocId);
6877 //==========================================================================
6879 // ufoInitHigherWords
6881 //==========================================================================
6882 UFO_DISABLE_INLINE void ufoInitHigherWords (void) {
6883 UFWORDX("(INCLUDE)", PAR_INCLUDE);
6885 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH);
6886 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID);
6887 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE);
6888 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME);
6890 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ);
6891 UFWORDX("($DEFINE)", PAR_DLR_DEFINE);
6892 UFWORDX("($UNDEF)", PAR_DLR_UNDEF);
6894 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM);
6895 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM);
6899 //==========================================================================
6901 // ufoInitStringWords
6903 //==========================================================================
6904 UFO_DISABLE_INLINE void ufoInitStringWords (void) {
6905 // create "STRING" vocabulary
6906 const uint32_t stringVocId = ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED);
6907 ufoVocSetOnlyDefs(stringVocId);
6908 UFWORDX("=", STREQU);
6909 UFWORDX("=CI", STREQUCI);
6910 UFWORDX("SEARCH", SEARCH);
6911 UFWORDX("HASH", STRHASH);
6912 UFWORDX("HASH-CI", STRHASHCI);
6913 ufoVocSetOnlyDefs(ufoForthVocId);
6917 //==========================================================================
6919 // ufoInitDebugWords
6921 //==========================================================================
6922 UFO_DISABLE_INLINE void ufoInitDebugWords (void) {
6923 // create "DEBUG" vocabulary
6924 const uint32_t debugVocId = ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED);
6925 ufoVocSetOnlyDefs(debugVocId);
6926 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA);
6927 UFWORDX("BACKTRACE", UFO_BACKTRACE);
6928 UFWORDX("DUMP-STACK", DUMP_STACK);
6929 UFWORDX("(BP)", MT_DEBUGGER_BP);
6930 UFWORDX("IP->NFA", IP2NFA);
6931 UFWORDX("IP->FILE/LINE", IP2FILELINE);
6932 ufoVocSetOnlyDefs(ufoForthVocId);
6936 //==========================================================================
6938 // ufoInitMTWords
6940 //==========================================================================
6941 UFO_DISABLE_INLINE void ufoInitMTWords (void) {
6942 // create "MTASK" vocabulary
6943 const uint32_t mtVocId = ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED);
6944 ufoVocSetOnlyDefs(mtVocId);
6945 UFWORDX("NEW-STATE", MT_NEW_STATE);
6946 UFWORDX("FREE-STATE", MT_FREE_STATE);
6947 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME);
6948 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME);
6949 UFWORDX("STATE-FIRST", MT_STATE_FIRST);
6950 UFWORDX("STATE-NEXT", MT_STATE_NEXT);
6951 UFWORDX("YIELD-TO", MT_YIELD_TO);
6952 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER);
6953 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE);
6954 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE);
6955 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE);
6956 UFWORDX("STATE-IP@", MT_STATE_IP_GET);
6957 UFWORDX("STATE-IP!", MT_STATE_IP_SET);
6958 UFWORDX("STATE-A>", MT_STATE_REGA_GET);
6959 UFWORDX("STATE->A", MT_STATE_REGA_SET);
6960 UFWORDX("STATE-USER@", MT_STATE_USER_GET);
6961 UFWORDX("STATE-USER!", MT_STATE_USER_SET);
6962 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET);
6963 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET);
6964 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM);
6965 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET);
6966 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET);
6967 UFWORDX("STATE-LP@", MT_LP_GET);
6968 UFWORDX("STATE-LBP@", MT_LBP_GET);
6969 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET);
6970 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET);
6971 UFWORDX("STATE-LP!", MT_LP_SET);
6972 UFWORDX("STATE-LBP!", MT_LBP_SET);
6973 UFWORDX("STATE-DS@", MT_DSTACK_LOAD);
6974 UFWORDX("STATE-RS@", MT_RSTACK_LOAD);
6975 UFWORDX("STATE-LS@", MT_LSTACK_LOAD);
6976 UFWORDX("STATE-DS!", MT_DSTACK_STORE);
6977 UFWORDX("STATE-RS!", MT_RSTACK_STORE);
6978 UFWORDX("STATE-LS!", MT_LSTACK_STORE);
6979 ufoVocSetOnlyDefs(ufoForthVocId);
6983 //==========================================================================
6985 // ufoInitTTYWords
6987 //==========================================================================
6988 UFO_DISABLE_INLINE void ufoInitTTYWords (void) {
6989 // create "TTY" vocabulary
6990 const uint32_t ttyVocId = ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED);
6991 ufoVocSetOnlyDefs(ttyVocId);
6992 UFWORDX("TTY?", TTY_TTYQ);
6993 UFWORDX("RAW?", TTY_RAWQ);
6994 UFWORDX("SIZE", TTY_SIZE);
6995 UFWORDX("SET-RAW", TTY_SET_RAW);
6996 UFWORDX("SET-COOKED", TTY_SET_COOKED);
6997 UFWORDX("RAW-EMIT", TTY_RAW_EMIT);
6998 UFWORDX("RAW-TYPE", TTY_RAW_TYPE);
6999 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH);
7000 UFWORDX("RAW-READCH", TTY_RAW_READCH);
7001 UFWORDX("RAW-READY?", TTY_RAW_READYQ);
7002 ufoVocSetOnlyDefs(ufoForthVocId);
7006 //==========================================================================
7008 // ufoInitVeryVeryHighWords
7010 //==========================================================================
7011 UFO_DISABLE_INLINE void ufoInitVeryVeryHighWords (void) {
7012 // interpret defer
7013 //ufoDefineDefer("INTERPRET", idumbCFA);
7015 ufoDefineEmitType();
7017 // ( addr count FALSE -- addr count FALSE / TRUE )
7018 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
7019 ufoDoneForth();
7020 // ( addr count FALSE -- addr count FALSE / TRUE )
7021 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
7022 ufoDoneForth();
7023 // ( FALSE -- FALSE / TRUE ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
7024 // return TRUE to stop calling other chained words, and omit default exit
7025 ufoDefineSColonForth("(EXIT-EXTENDER)");
7026 ufoDoneForth();
7028 // create "FORTH:EXIT"
7029 // : EXIT ?COMP COMPILE FORTH:(EXIT) ;
7030 ufoDefineForthImm("EXIT");
7031 UFC("COMPILER:?COMP");
7032 UFC("FALSE"); UFC("(EXIT-EXTENDER)");
7033 UFC("FORTH:(TBRANCH)"); const uint32_t exit_branch_end = ufoMarkFwd();
7034 UFC("FORTH:(LITCFA)"); UFC("FORTH:(EXIT)");
7035 UFC("FORTH:COMPILE,");
7036 ufoResolveFwd(exit_branch_end);
7037 ufoDoneForth();
7039 ufoDefineInterpret();
7041 //ufoDumpVocab(ufoCompilerVocId);
7043 ufoDefineForth("RUN-INTERPRET-LOOP");
7044 const uint32_t addrAgain = UFO_GET_DP();
7045 UFC("RP0!");
7046 UFC("INTERPRET");
7047 UFC("FORTH:(BRANCH)");
7048 ufoImgEmitU32(addrAgain);
7049 ufoDoneForth();
7052 #define UFO_ADD_DO_CFA(cfx_) do { \
7053 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
7054 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
7055 ufoCFAsUsed += 1; \
7056 } while (0)
7059 //==========================================================================
7061 // ufoInitCommon
7063 //==========================================================================
7064 UFO_DISABLE_INLINE void ufoInitCommon (void) {
7065 ufoVSP = 0;
7066 ufoForthVocId = 0; ufoCompilerVocId = 0;
7068 ufoForthCFAs = calloc(UFO_MAX_NATIVE_CFAS, sizeof(ufoForthCFAs[0]));
7070 // allocate default TIB handle
7071 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
7072 //ufoDefTIB = tibh->ufoHandle;
7074 ufoForthCFAs[0] = NULL; ufoCFAsUsed = 1u;
7075 UFO_ADD_DO_CFA(Forth);
7076 UFO_ADD_DO_CFA(Variable);
7077 UFO_ADD_DO_CFA(Value);
7078 UFO_ADD_DO_CFA(Const);
7079 UFO_ADD_DO_CFA(Defer);
7080 UFO_ADD_DO_CFA(Voc);
7081 UFO_ADD_DO_CFA(Create);
7082 UFO_ADD_DO_CFA(UserVariable);
7084 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
7086 ufoInitBaseDict();
7088 // create "FORTH" vocabulary
7089 ufoForthVocId = ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED);
7090 ufoVocSetOnlyDefs(ufoForthVocId);
7092 // base low-level interpreter words
7093 ufoInitBasicWords();
7095 // some COMPILER words
7096 ufoInitBasicCompilerWords();
7098 // STRING vocabulary
7099 ufoInitStringWords();
7101 // DEBUG vocabulary
7102 ufoInitDebugWords();
7104 // MTASK vocabulary
7105 ufoInitMTWords();
7107 // HANDLE vocabulary
7108 ufoInitHandleWords();
7110 // TTY vocabulary
7111 ufoInitTTYWords();
7113 // more FORTH words
7114 ufoInitMoreWords();
7116 // some higher-level FORTH words (includes, etc.)
7117 ufoInitHigherWords();
7119 // very-very high-level FORTH words
7120 ufoInitVeryVeryHighWords();
7122 #if 0
7123 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
7124 #endif
7126 ufoReset();
7129 #undef UFC
7132 // ////////////////////////////////////////////////////////////////////////// //
7133 // virtual machine executor
7137 //==========================================================================
7139 // ufoRunVM
7141 // address interpreter
7143 //==========================================================================
7144 static void ufoRunVMCFA (uint32_t cfa) {
7145 const uint32_t oldRPTop = ufoRPTop;
7146 ufoRPTop = ufoRP;
7147 #ifdef UFO_TRACE_VM_RUN
7148 fprintf(stderr, "**VM-INITIAL**: cfa=%u\n", cfa);
7149 UFCALL(DUMP_STACK);
7150 #endif
7151 ufoRPush(cfa);
7152 ufoVMRPopCFA = 1;
7153 ufoVMStop = 0;
7154 // VM execution loop
7155 do {
7156 if (ufoVMAbort) ufoFatal("user abort");
7157 if (ufoVMStop) { ufoRP = oldRPTop; break; }
7158 if (ufoCurrState == NULL) ufoFatal("execution state is lost");
7159 if (ufoVMRPopCFA == 0) {
7160 // check IP
7161 if (ufoIP == 0) ufoFatal("IP is NULL");
7162 if (ufoIP & UFO_ADDR_HANDLE_BIT) ufoFatal("IP is a handle");
7163 cfa = ufoImgGetU32(ufoIP); ufoIP += 4u;
7164 } else {
7165 cfa = ufoRPop(); ufoVMRPopCFA = 0;
7167 // check CFA sanity
7168 if (cfa == 0) ufoFatal("EXECUTE: NULL CFA");
7169 if (cfa & UFO_ADDR_HANDLE_BIT) ufoFatal("cannot execute handle");
7170 // get next word CFAIDX, and check it
7171 uint32_t cfaidx = ufoImgGetU32(cfa);
7172 if (cfaidx & UFO_ADDR_HANDLE_BIT) ufoFatal("cannot execute CFAIDX-handle");
7173 #ifdef UFO_TRACE_VM_RUN
7174 fprintf(stderr, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP - 4u, cfa, cfaidx);
7175 UFCALL(DUMP_STACK);
7176 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa));
7177 fprintf(stderr, "######################################\n");
7178 #endif
7179 if (cfaidx & UFO_ADDR_CFA_BIT) {
7180 cfaidx &= UFO_ADDR_CFA_MASK;
7181 if (cfaidx >= ufoCFAsUsed || ufoForthCFAs[cfaidx] == NULL) {
7182 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
7183 cfaidx, ufoCFAsUsed, ufoIP - 4u);
7185 #ifdef UFO_TRACE_VM_RUN
7186 fprintf(stderr, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx,
7187 (ufoDoForthCFA & UFO_ADDR_CFA_MASK));
7188 #endif
7189 ufoForthCFAs[cfaidx](UFO_CFA_TO_PFA(cfa));
7190 } else {
7191 // if CFA points somewhere inside a dict, this is "DOES>" word
7192 // IP points to PFA we need to push
7193 // CFA points to Forth word we need to jump to
7194 #ifdef UFO_TRACE_VM_DOER
7195 fprintf(stderr, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP, cfa, cfaidx);
7196 UFCALL(UFO_BACKTRACE);
7197 #endif
7198 ufoPush(UFO_CFA_TO_PFA(cfa)); // push PFA
7199 ufoRPush(ufoIP); // push IP
7200 ufoIP = cfaidx; // fix IP
7202 // that's all we need to activate the debugger
7203 if (ufoSingleStep) {
7204 ufoSingleStep -= 1;
7205 if (ufoSingleStep == 0 && ufoDebuggerState != NULL) {
7206 if (ufoCurrState == ufoDebuggerState) ufoFatal("debugger cannot debug itself");
7207 UfoState *ost = ufoCurrState;
7208 ufoSwitchToState(ufoDebuggerState); // always use API call for this!
7209 ufoPush(-2);
7210 ufoPush(ost->id);
7213 } while (ufoRP != oldRPTop);
7214 //ufoVMStop = 0;
7218 // ////////////////////////////////////////////////////////////////////////// //
7219 // high-level API
7222 //==========================================================================
7224 // ufoRegisterWord
7226 // register new word
7228 //==========================================================================
7229 uint32_t ufoRegisterWord (const char *wname, ufoNativeCFA cfa, uint32_t flags) {
7230 ufo_assert(cfa != NULL);
7231 ufo_assert(wname != NULL && wname[0] != 0);
7232 uint32_t cfaidx = ufoCFAsUsed;
7233 if (cfaidx >= UFO_MAX_NATIVE_CFAS) ufoFatal("too many native words");
7234 ufoForthCFAs[cfaidx] = cfa;
7235 ufoCFAsUsed += 1;
7236 //ufoDefineNative(wname, xcfa, 0);
7237 cfaidx |= UFO_ADDR_CFA_BIT;
7238 flags &= 0xffffff00u;
7239 ufoCreateWordHeader(wname, flags);
7240 const uint32_t res = UFO_GET_DP();
7241 ufoImgEmitU32(cfaidx);
7242 return res;
7246 //==========================================================================
7248 // ufoRegisterDataWord
7250 //==========================================================================
7251 static uint32_t ufoRegisterDataWord (const char *wname, uint32_t cfaidx, uint32_t value,
7252 uint32_t flags)
7254 ufo_assert(wname != NULL && wname[0] != 0);
7255 flags &= 0xffffff00u;
7256 ufoCreateWordHeader(wname, flags);
7257 ufoImgEmitU32(cfaidx);
7258 const uint32_t res = UFO_GET_DP();
7259 ufoImgEmitU32(value);
7260 return res;
7264 //==========================================================================
7266 // ufoRegisterConstant
7268 //==========================================================================
7269 void ufoRegisterConstant (const char *wname, uint32_t value, uint32_t flags) {
7270 (void)ufoRegisterDataWord(wname, ufoDoConstCFA, value, flags);
7274 //==========================================================================
7276 // ufoRegisterVariable
7278 //==========================================================================
7279 uint32_t ufoRegisterVariable (const char *wname, uint32_t value, uint32_t flags) {
7280 return ufoRegisterDataWord(wname, ufoDoVariableCFA, value, flags);
7284 //==========================================================================
7286 // ufoRegisterValue
7288 //==========================================================================
7289 uint32_t ufoRegisterValue (const char *wname, uint32_t value, uint32_t flags) {
7290 return ufoRegisterDataWord(wname, ufoDoValueCFA, value, flags);
7294 //==========================================================================
7296 // ufoRegisterDefer
7298 //==========================================================================
7299 uint32_t ufoRegisterDefer (const char *wname, uint32_t value, uint32_t flags) {
7300 return ufoRegisterDataWord(wname, ufoDoDeferCFA, value, flags);
7304 //==========================================================================
7306 // ufoFindWordInVocabulary
7308 // check if we have the corresponding word.
7309 // return CFA suitable for executing, or 0.
7311 //==========================================================================
7312 uint32_t ufoFindWordInVocabulary (const char *wname, uint32_t vocid) {
7313 if (wname == NULL || wname[0] == 0) return 0;
7314 size_t wlen = strlen(wname);
7315 if (wlen >= UFO_MAX_WORD_LENGTH) return 0;
7316 return ufoFindWordInVocAndParents(wname, (uint32_t)wlen, 0, vocid, 0);
7320 //==========================================================================
7322 // ufoGetIP
7324 //==========================================================================
7325 uint32_t ufoGetIP (void) {
7326 return ufoIP;
7330 //==========================================================================
7332 // ufoSetIP
7334 //==========================================================================
7335 void ufoSetIP (uint32_t newip) {
7336 ufoIP = newip;
7340 //==========================================================================
7342 // ufoIsExecuting
7344 //==========================================================================
7345 int ufoIsExecuting (void) {
7346 return (ufoImgGetU32(ufoAddrSTATE) == 0);
7350 //==========================================================================
7352 // ufoIsCompiling
7354 //==========================================================================
7355 int ufoIsCompiling (void) {
7356 return (ufoImgGetU32(ufoAddrSTATE) != 0);
7360 //==========================================================================
7362 // ufoSetExecuting
7364 //==========================================================================
7365 void ufoSetExecuting (void) {
7366 ufoImgPutU32(ufoAddrSTATE, 0);
7370 //==========================================================================
7372 // ufoSetCompiling
7374 //==========================================================================
7375 void ufoSetCompiling (void) {
7376 ufoImgPutU32(ufoAddrSTATE, 1);
7380 //==========================================================================
7382 // ufoGetHere
7384 //==========================================================================
7385 uint32_t ufoGetHere () {
7386 return UFO_GET_DP();
7390 //==========================================================================
7392 // ufoGetPad
7394 //==========================================================================
7395 uint32_t ufoGetPad () {
7396 UFCALL(PAD);
7397 return ufoPop();
7401 //==========================================================================
7403 // ufoTIBPeekCh
7405 //==========================================================================
7406 uint8_t ufoTIBPeekCh (uint32_t ofs) {
7407 return ufoTibPeekChOfs(ofs);
7411 //==========================================================================
7413 // ufoTIBGetCh
7415 //==========================================================================
7416 uint8_t ufoTIBGetCh (void) {
7417 return ufoTibGetCh();
7421 //==========================================================================
7423 // ufoTIBSkipCh
7425 //==========================================================================
7426 void ufoTIBSkipCh (void) {
7427 ufoTibSkipCh();
7431 //==========================================================================
7433 // ufoTIBSRefill
7435 // returns 0 on EOF
7437 //==========================================================================
7438 int ufoTIBSRefill (int allowCrossIncludes) {
7439 return ufoLoadNextLine(allowCrossIncludes);
7443 //==========================================================================
7445 // ufoPeekData
7447 //==========================================================================
7448 uint32_t ufoPeekData (void) {
7449 return ufoPeek();
7453 //==========================================================================
7455 // ufoPopData
7457 //==========================================================================
7458 uint32_t ufoPopData (void) {
7459 return ufoPop();
7463 //==========================================================================
7465 // ufoPushData
7467 //==========================================================================
7468 void ufoPushData (uint32_t value) {
7469 return ufoPush(value);
7473 //==========================================================================
7475 // ufoPushBoolData
7477 //==========================================================================
7478 void ufoPushBoolData (int val) {
7479 ufoPushBool(val);
7483 //==========================================================================
7485 // ufoPeekRet
7487 //==========================================================================
7488 uint32_t ufoPeekRet (void) {
7489 return ufoRPeek();
7493 //==========================================================================
7495 // ufoPopRet
7497 //==========================================================================
7498 uint32_t ufoPopRet (void) {
7499 return ufoRPop();
7503 //==========================================================================
7505 // ufoPushRet
7507 //==========================================================================
7508 void ufoPushRet (uint32_t value) {
7509 return ufoRPush(value);
7513 //==========================================================================
7515 // ufoPushBoolRet
7517 //==========================================================================
7518 void ufoPushBoolRet (int val) {
7519 ufoRPush(val ? ufoTrueValue : 0);
7523 //==========================================================================
7525 // ufoPeekByte
7527 //==========================================================================
7528 uint8_t ufoPeekByte (uint32_t addr) {
7529 return ufoImgGetU8Ext(addr);
7533 //==========================================================================
7535 // ufoPeekWord
7537 //==========================================================================
7538 uint16_t ufoPeekWord (uint32_t addr) {
7539 ufoPush(addr);
7540 UFCALL(WPEEK);
7541 return ufoPop();
7545 //==========================================================================
7547 // ufoPeekCell
7549 //==========================================================================
7550 uint32_t ufoPeekCell (uint32_t addr) {
7551 ufoPush(addr);
7552 UFCALL(PEEK);
7553 return ufoPop();
7557 //==========================================================================
7559 // ufoPokeByte
7561 //==========================================================================
7562 void ufoPokeByte (uint32_t addr, uint32_t value) {
7563 ufoImgPutU8(addr, value);
7567 //==========================================================================
7569 // ufoPokeWord
7571 //==========================================================================
7572 void ufoPokeWord (uint32_t addr, uint32_t value) {
7573 ufoPush(value);
7574 ufoPush(addr);
7575 UFCALL(WPOKE);
7579 //==========================================================================
7581 // ufoPokeCell
7583 //==========================================================================
7584 void ufoPokeCell (uint32_t addr, uint32_t value) {
7585 ufoPush(value);
7586 ufoPush(addr);
7587 UFCALL(POKE);
7591 //==========================================================================
7593 // ufoEmitByte
7595 //==========================================================================
7596 void ufoEmitByte (uint32_t value) {
7597 ufoImgEmitU8(value);
7601 //==========================================================================
7603 // ufoEmitWord
7605 //==========================================================================
7606 void ufoEmitWord (uint32_t value) {
7607 ufoImgEmitU8(value & 0xff);
7608 ufoImgEmitU8((value >> 8) & 0xff);
7612 //==========================================================================
7614 // ufoEmitCell
7616 //==========================================================================
7617 void ufoEmitCell (uint32_t value) {
7618 ufoImgEmitU32(value);
7622 //==========================================================================
7624 // ufoIsInited
7626 //==========================================================================
7627 int ufoIsInited (void) {
7628 return (ufoMode != UFO_MODE_NONE);
7632 static void (*ufoUserPostInitCB) (void);
7635 //==========================================================================
7637 // ufoSetUserPostInit
7639 // called after main initialisation
7641 //==========================================================================
7642 void ufoSetUserPostInit (void (*cb) (void)) {
7643 ufoUserPostInitCB = cb;
7647 //==========================================================================
7649 // ufoInit
7651 //==========================================================================
7652 void ufoInit (void) {
7653 if (ufoMode != UFO_MODE_NONE) return;
7654 ufoMode = UFO_MODE_NATIVE;
7656 ufoInFileLine = 0;
7657 ufoInFileName = NULL;
7658 ufoInFile = NULL;
7659 ufoLastIncPath = NULL; ufoLastSysIncPath = NULL;
7661 for (uint32_t f = 0; f < UFO_MAX_STATES; f += 1u) ufoStateMap[f] = NULL;
7662 memset(ufoStateUsedBitmap, 0, sizeof(ufoStateUsedBitmap));
7664 ufoCurrState = ufoNewState(0); // CFA doesn't matter here
7665 strcpy(ufoCurrState->name, "MAIN");
7666 ufoInitStateUserVars(ufoCurrState, 1);
7667 ufoImgPutU32(ufoAddrDefTIB, 0); // create TIB handle
7668 ufoImgPutU32(ufoAddrTIBx, 0); // create TIB handle
7670 ufoYieldedState = NULL;
7671 ufoDebuggerState = NULL;
7672 ufoSingleStep = 0;
7674 #ifdef UFO_DEBUG_STARTUP_TIMES
7675 uint32_t stt = ufo_get_msecs();
7676 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
7677 #endif
7678 ufoInitCommon();
7679 #ifdef UFO_DEBUG_STARTUP_TIMES
7680 uint32_t ett = ufo_get_msecs();
7681 fprintf(stderr, "UrForth init time: %u msecs\n", (unsigned)(ett - stt));
7682 #endif
7684 ufoReset();
7686 if (ufoUserPostInitCB) {
7687 ufoUserPostInitCB();
7688 ufoReset();
7691 // load ufo modules
7692 char *ufmname = ufoCreateIncludeName("init", 1, NULL);
7693 #ifdef WIN32
7694 FILE *ufl = fopen(ufmname, "rb");
7695 #else
7696 FILE *ufl = fopen(ufmname, "r");
7697 #endif
7698 if (ufl) {
7699 ufoPushInFile();
7700 ufoInFileName = ufmname;
7701 ufoInFile = ufl;
7702 ufoFileId = ufoLastUsedFileId;
7703 setLastIncPath(ufoInFileName, 1);
7704 } else {
7705 free(ufmname);
7706 ufoFatal("cannot load init code");
7709 if (ufoInFile != NULL) {
7710 ufoRunInterpretLoop();
7715 //==========================================================================
7717 // ufoFinishVM
7719 //==========================================================================
7720 void ufoFinishVM (void) {
7721 ufoVMStop = 1;
7725 //==========================================================================
7727 // ufoWasVMFinished
7729 // check if VM was exited due to `ufoFinishVM()`
7731 //==========================================================================
7732 int ufoWasVMFinished (void) {
7733 return (ufoVMStop != 0);
7737 //==========================================================================
7739 // ufoCallParseIntr
7741 // ( -- addr count TRUE / FALSE )
7742 // does base TIB parsing; never copies anything.
7743 // as our reader is line-based, returns FALSE on EOL.
7744 // EOL is detected after skipping leading delimiters.
7745 // passing -1 as delimiter skips the whole line, and always returns FALSE.
7746 // trailing delimiter is always skipped.
7747 // result is on the data stack.
7749 //==========================================================================
7750 void ufoCallParseIntr (uint32_t delim, int skipLeading) {
7751 ufoPush(delim); ufoPushBool(skipLeading);
7752 UFCALL(PAR_PARSE);
7755 //==========================================================================
7757 // ufoCallParseName
7759 // ( -- addr count )
7760 // parse with leading blanks skipping. doesn't copy anything.
7761 // return empty string on EOL.
7763 //==========================================================================
7764 void ufoCallParseName (void) {
7765 UFCALL(PARSE_NAME);
7769 //==========================================================================
7771 // ufoCallParse
7773 // ( -- addr count TRUE / FALSE )
7774 // parse without skipping delimiters; never copies anything.
7775 // as our reader is line-based, returns FALSE on EOL.
7776 // passing 0 as delimiter skips the whole line, and always returns FALSE.
7777 // trailing delimiter is always skipped.
7779 //==========================================================================
7780 void ufoCallParse (uint32_t delim) {
7781 ufoPush(delim);
7782 UFCALL(PARSE);
7786 //==========================================================================
7788 // ufoCallParseSkipBlanks
7790 //==========================================================================
7791 void ufoCallParseSkipBlanks (void) {
7792 UFCALL(PARSE_SKIP_BLANKS);
7796 //==========================================================================
7798 // ufoCallParseSkipComments
7800 //==========================================================================
7801 void ufoCallParseSkipComments (void) {
7802 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS);
7806 //==========================================================================
7808 // ufoCallParseSkipLineComments
7810 //==========================================================================
7811 void ufoCallParseSkipLineComments (void) {
7812 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
7816 //==========================================================================
7818 // ufoCallParseSkipLine
7820 // to the end of line; doesn't refill
7822 //==========================================================================
7823 void ufoCallParseSkipLine (void) {
7824 UFCALL(PARSE_SKIP_LINE);
7828 //==========================================================================
7830 // ufoCallBasedNumber
7832 // convert number from addrl+1
7833 // returns address of the first inconvertible char
7834 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
7836 //==========================================================================
7837 void ufoCallBasedNumber (uint32_t addr, uint32_t count, int allowSign, int base) {
7838 ufoPush(addr); ufoPush(count); ufoPushBool(allowSign);
7839 if (base < 0) ufoPush(0); else ufoPush((uint32_t)base);
7840 UFCALL(PAR_BASED_NUMBER);
7844 //==========================================================================
7846 // ufoRunWord
7848 //==========================================================================
7849 void ufoRunWord (uint32_t cfa) {
7850 if (cfa != 0) {
7851 if (ufoMode == UFO_MODE_NONE) ufoFatal("UrForth is not properly inited");
7852 if (ufoInRunWord) ufoFatal("`ufoRunWord` cannot be called recursively");
7853 ufoMode = UFO_MODE_NATIVE;
7854 ufoInRunWord = 1;
7855 ufoRunVMCFA(cfa);
7856 ufoInRunWord = 0;
7861 //==========================================================================
7863 // ufoRunMacroWord
7865 //==========================================================================
7866 void ufoRunMacroWord (uint32_t cfa) {
7867 if (cfa != 0) {
7868 if (ufoMode == UFO_MODE_NONE) ufoFatal("UrForth is not properly inited");
7869 if (ufoInRunWord) ufoFatal("`ufoRunWord` cannot be called recursively");
7870 ufoMode = UFO_MODE_MACRO;
7871 const uint32_t oisp = ufoFileStackPos;
7872 ufoPushInFile();
7873 ufoFileId = 0;
7874 (void)ufoLoadNextUserLine();
7875 ufoInRunWord = 1;
7876 ufoRunVMCFA(cfa);
7877 ufoInRunWord = 0;
7878 ufoPopInFile();
7879 ufo_assert(ufoFileStackPos == oisp); // sanity check
7884 //==========================================================================
7886 // ufoIsInMacroMode
7888 // check if we are currently in "MACRO" mode.
7889 // should be called from registered words.
7891 //==========================================================================
7892 int ufoIsInMacroMode (void) {
7893 return (ufoMode == UFO_MODE_MACRO);
7897 //==========================================================================
7899 // ufoRunInterpretLoop
7901 // run default interpret loop.
7903 //==========================================================================
7904 void ufoRunInterpretLoop (void) {
7905 if (ufoMode == UFO_MODE_NONE) {
7906 ufoInit();
7908 const uint32_t cfa = ufoFindWord("RUN-INTERPRET-LOOP");
7909 if (cfa == 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
7910 ufoReset();
7911 ufoMode = UFO_MODE_NATIVE;
7912 ufoInRunWord = 1;
7913 ufoRunVMCFA(cfa);
7914 ufoInRunWord = 0;
7915 while (ufoFileStackPos != 0) ufoPopInFile();
7919 //==========================================================================
7921 // ufoRunFile
7923 //==========================================================================
7924 void ufoRunFile (const char *fname) {
7925 if (ufoMode == UFO_MODE_NONE) {
7926 ufoInit();
7928 if (ufoInRunWord) ufoFatal("`ufoRunFile` cannot be called recursively");
7929 ufoMode = UFO_MODE_NATIVE;
7931 ufoReset();
7932 char *ufmname = ufoCreateIncludeName(fname, 0, ".");
7933 #ifdef WIN32
7934 FILE *ufl = fopen(ufmname, "rb");
7935 #else
7936 FILE *ufl = fopen(ufmname, "r");
7937 #endif
7938 if (ufl) {
7939 ufoPushInFile();
7940 ufoInFileName = ufmname;
7941 ufoInFile = ufl;
7942 ufoFileId = ufoLastUsedFileId;
7943 setLastIncPath(ufoInFileName, 0);
7944 } else {
7945 free(ufmname);
7946 ufoFatal("cannot load source file '%s'", fname);
7948 ufoRunInterpretLoop();