urasm: more forth macro code
[urasm.git] / src / liburforth / urforth.c
blob38a8f04100153433b3a970f3848f3bd0fa29e3ef
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/fcntl.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
19 #include "urforth.h"
21 #ifdef WIN32
22 # define realpath(shit,fuck) _fullpath(fuck, shit, 32768)
23 #endif
26 //#define UFO_DEBUG_WRITE_MAIN_IMAGE
27 //#define UFO_DEBUG_WRITE_DEBUG_IMAGE
30 #define UFO_DEBUG_STARTUP_TIMES
31 //#define UFO_DEBUG_FATAL_ABORT
32 #define UFO_DEBUG_DEBUG /* ;-) */
33 //#define UFO_TRACE_VM_DOER
34 //#define UFO_TRACE_VM_RUN
35 //#define UFO_DEBUG_INCLUDE
36 //#define UFO_DEBUG_DUMP_NEW_HEADERS
37 //#define UFO_DEBUG_FIND_WORD
38 //#define UFO_DEBUG_FIND_WORD_IN_VOC
39 //#define UFO_DEBUG_FIND_WORD_COLON
41 // 2/8 msecs w/o inlining
42 // 1/5 msecs with inlining
43 #if 1
44 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
45 #else
46 # define UFO_FORCE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
47 #endif
48 #define UFO_DISABLE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
50 // detect arch, and use faster memory access code on x86
51 #if defined(__x86_64__) || defined(_M_X64) || \
52 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
53 # define UFO_FAST_MEM_ACCESS
54 #endif
56 // should not be bigger than this!
57 #define UFO_MAX_WORD_LENGTH (250)
59 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
62 // ////////////////////////////////////////////////////////////////////////// //
63 static void ufoFlushOutput (void);
65 UFO_DISABLE_INLINE const char *ufo_assert_failure (const char *cond, const char *fname,
66 int fline, const char *func)
68 for (const char *t = fname; *t; ++t) {
69 #ifdef WIN32
70 if (*t == '/' || *t == '\\') fname = t+1;
71 #else
72 if (*t == '/') fname = t+1;
73 #endif
75 ufoFlushOutput();
76 fprintf(stderr, "\n%s:%d: Assertion in `%s` failed: %s\n", fname, fline, func, cond);
77 ufoFlushOutput();
78 abort();
81 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
84 static char ufoRealPathBuf[32769];
85 static char ufoRealPathHashBuf[32769];
88 //==========================================================================
90 // ufoRealPath
92 //==========================================================================
93 static char *ufoRealPath (const char *fname) {
94 char *res;
95 if (fname != NULL && fname[0] != 0) {
96 res = realpath(fname, NULL);
97 if (res != NULL) {
98 const size_t slen = strlen(res);
99 if (slen < 32768) {
100 strcpy(ufoRealPathBuf, res);
101 free(res);
102 res = ufoRealPathBuf;
103 } else {
104 free(res);
105 res = NULL;
108 } else {
109 res = NULL;
111 return res;
115 #ifndef WIN32
116 static time_t secstart = 0;
117 #endif
121 //==========================================================================
123 // ufo_get_msecs
125 //==========================================================================
126 static uint64_t ufo_get_msecs (void) {
127 #ifdef WIN32
128 return GetTickCount();
129 #else
130 struct timespec ts;
131 #ifdef CLOCK_MONOTONIC
132 ufo_assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
133 #else
134 // this should be available everywhere
135 ufo_assert(clock_gettime(CLOCK_REALTIME, &ts) == 0);
136 #endif
137 // first run?
138 if (secstart == 0) {
139 secstart = ts.tv_sec+1;
140 ufo_assert(secstart); // it should not be zero
142 return (uint64_t)(ts.tv_sec-secstart+2)*1000U+(uint32_t)ts.tv_nsec/1000000U;
143 // nanoseconds
144 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
145 #endif
149 //==========================================================================
151 // joaatHashBuf
153 //==========================================================================
154 UFO_FORCE_INLINE uint32_t joaatHashBuf (const void *buf, size_t len, uint8_t orbyte) {
155 uint32_t hash = 0x29a;
156 const uint8_t *s = (const uint8_t *)buf;
157 while (len--) {
158 hash += (*s++)|orbyte;
159 hash += hash<<10;
160 hash ^= hash>>6;
162 // finalize
163 hash += hash<<3;
164 hash ^= hash>>11;
165 hash += hash<<15;
166 return hash;
170 // this converts ASCII capitals to locase (and destroys other, but who cares)
171 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
174 //==========================================================================
176 // toUpper
178 //==========================================================================
179 UFO_FORCE_INLINE char toUpper (char ch) {
180 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
184 //==========================================================================
186 // toUpperU8
188 //==========================================================================
189 UFO_FORCE_INLINE uint8_t toUpperU8 (uint8_t ch) {
190 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
194 //==========================================================================
196 // digitInBase
198 //==========================================================================
199 UFO_FORCE_INLINE int digitInBase (char ch, int base) {
200 switch (ch) {
201 case '0' ... '9': ch = ch - '0'; break;
202 case 'A' ... 'Z': ch = ch - 'A' + 10; break;
203 case 'a' ... 'z': ch = ch - 'a' + 10; break;
204 default: base = -1; break;
206 return (ch >= 0 && ch < base ? ch : -1);
211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
212 ;; word header format:
213 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
214 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
215 ;; exact uppercase, only something that resembles it)
216 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
217 ;; before nfa, we have such "hidden" fields:
218 ;; dd xfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
219 ;; dd yfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
220 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
221 ;; ; if there is no hashtable, this field is not used
222 ;; lfa:
223 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
224 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
225 ;; nfa:
226 ;; dd flags-and-name-len ; see below
227 ;; db name ; no terminating zero or other "termination flag" here
228 ;; here could be some 0 bytes to align everything to 4 bytes
229 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
230 ;; ; full length, including padding, but not including this byte
231 ;; cfa:
232 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
233 ;; pfa:
234 ;; word data follows
236 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
237 ;; layout:
238 ;; db namelen
239 ;; db argtype
240 ;; dw flags
241 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
243 ;; flags:
244 ;; bit 0: immediate
245 ;; bit 1: smudge
246 ;; bit 2: noreturn
247 ;; bit 3: hidden
248 ;; bit 4: codeblock
249 ;; bit 5: vocabulary
250 ;; bit 6: *UNUSED* main scattered colon word (with "...")
251 ;; bit 7: protected
253 ;; argtype is the type of the argument that this word reads from the threaded code.
254 ;; possible argument types:
255 ;; 0: none
256 ;; 1: branch address
257 ;; 2: cell-size numeric literal
258 ;; 3: cell-counted string with terminating zero (not counted)
259 ;; 4: cfa of another word
260 ;; 5: cblock
261 ;; 6: vocid
262 ;; 7: byte-counted string with terminating zero (not counted)
263 ;; 8: data skip: the arg is amout of bytes to skip (not including the counter itself)
266 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
267 ;; wordlist structure (at PFA)
268 ;; -4: wordlist type id (used by structs, for example)
269 ;; dd latest
270 ;; dd voclink (voclink always points here)
271 ;; dd parent (if not zero, all parent words are visible)
272 ;; dd header-nfa (can be 0 for anonymous wordlists)
273 ;; hashtable (if enabled), or ~0U if no hash table
277 // ////////////////////////////////////////////////////////////////////////// //
278 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
279 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
280 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
281 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
282 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
283 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
284 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
285 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
286 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
287 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
288 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
289 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
290 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
291 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
292 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
293 #define UFO_XFA_TO_WST(xfa_) ((xfa_) - 4u)
294 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 2u * 4u)
295 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
298 // ////////////////////////////////////////////////////////////////////////// //
299 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
300 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
301 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
302 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
303 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
305 #define UFO_HASHTABLE_SIZE (256)
307 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
309 #define UFO_MAX_NATIVE_CFAS (1024u)
310 static ufoNativeCFA *ufoForthCFAs = NULL;
311 static uint32_t ufoCFAsUsed = 0;
313 static uint32_t ufoDoForthCFA;
314 static uint32_t ufoDoVariableCFA;
315 static uint32_t ufoDoValueCFA;
316 static uint32_t ufoDoConstCFA;
317 static uint32_t ufoDoDeferCFA;
318 static uint32_t ufoDoVocCFA;
319 static uint32_t ufoDoCreateCFA;
320 static uint32_t ufoDoUserVariableCFA;
322 static uint32_t ufoLitStr8CFA;
324 // special address types:
325 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
326 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
328 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
329 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
330 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
331 #define UFO_ADDR_HANDLE_SHIFT (12)
332 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
334 // temporary area is 1MB buffer out of the main image
335 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
336 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
338 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
341 static uint32_t *ufoImage = NULL;
342 static uint32_t ufoImageSize = 0;
344 static uint8_t *ufoDebugImage = NULL;
345 static uint32_t ufoDebugImageUsed = 0; // in bytes
346 static uint32_t ufoDebugImageSize = 0; // in bytes
347 static uint32_t ufoDebugFileNameHash = 0; // current file name hash
348 static uint32_t ufoDebugFileNameLen = 0; // current file name length
349 static uint32_t ufoDebugLastLine = 0;
350 static uint32_t ufoDebugLastLinePCOfs = 0;
351 static uint32_t ufoDebugLastLineDP = 0;
352 static uint32_t ufoDebugCurrDP = 0;
354 static uint32_t ufoInRunWord = 0;
356 static volatile int ufoVMAbort = 0;
357 static volatile int ufoVMStop = 0;
359 #define ufoTrueValue (~(uint32_t)0)
361 enum {
362 UFO_MODE_NONE = -1,
363 UFO_MODE_NATIVE = 0, // executing forth code
364 UFO_MODE_MACRO = 1, // executing forth asm macro
366 static uint32_t ufoMode = UFO_MODE_NONE;
368 #define UFO_DSTACK_SIZE (8192)
369 #define UFO_RSTACK_SIZE (4096)
370 #define UFO_LSTACK_SIZE (4096)
371 #define UFO_MAX_TASK_NAME (127)
372 #define UFO_VOCSTACK_SIZE (16u)
374 // to support multitasking (required for the debugger),
375 // our virtual machine state is encapsulated in a struct.
376 typedef struct UfoState_t {
377 uint32_t id;
378 uint32_t dStack[UFO_DSTACK_SIZE];
379 uint32_t rStack[UFO_RSTACK_SIZE];
380 uint32_t lStack[UFO_LSTACK_SIZE];
381 uint32_t IP; // in image
382 uint32_t SP; // points AFTER the last value pushed
383 uint32_t RP; // points AFTER the last value pushed
384 uint32_t RPTop; // stop when RP is this
385 // address register
386 uint32_t regA;
387 // for locals
388 uint32_t LP;
389 uint32_t LBP;
390 uint32_t vmRPopCFA;
391 // vocstack
392 uint32_t vocStack[UFO_VOCSTACK_SIZE]; // cfas
393 uint32_t VSP;
394 // temp image
395 uint32_t *imageTemp;
396 uint32_t imageTempSize;
397 // linked list of all allocated states (tasks)
398 char name[UFO_MAX_TASK_NAME + 1];
399 } UfoState;
401 // 'cmon!
402 #define UFO_MAX_STATES (8192)
404 // this is indexed by id
405 static UfoState *ufoStateMap[UFO_MAX_STATES] = {NULL};
406 static uint32_t ufoStateUsedBitmap[UFO_MAX_STATES/32] = {0};
408 // currently active execution state
409 static UfoState *ufoCurrState = NULL;
410 // state we're yielded from
411 static UfoState *ufoYieldedState = NULL;
412 // if debug state is not NULL, VM will switch to it
413 // after executing one instruction from the current state.
414 // it will store current state in `ufoDebugeeState`.
415 static UfoState *ufoDebuggerState = NULL;
416 static uint32_t ufoSingleStep = 0;
418 #define ufoDStack (ufoCurrState->dStack)
419 #define ufoRStack (ufoCurrState->rStack)
420 #define ufoLStack (ufoCurrState->lStack)
421 #define ufoIP (ufoCurrState->IP)
422 #define ufoSP (ufoCurrState->SP)
423 #define ufoRP (ufoCurrState->RP)
424 #define ufoRPTop (ufoCurrState->RPTop)
425 #define ufoLP (ufoCurrState->LP)
426 #define ufoLBP (ufoCurrState->LBP)
427 #define ufoRegA (ufoCurrState->regA)
428 #define ufoImageTemp (ufoCurrState->imageTemp)
429 #define ufoImageTempSize (ufoCurrState->imageTempSize)
430 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
431 #define ufoVocStack (ufoCurrState->vocStack)
432 #define ufoVSP (ufoCurrState->VSP)
434 // 256 bytes for user variables
435 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
436 #define UFO_USER_AREA_SIZE (256u)
437 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
438 #define UFO_NBUF_SIZE (256u)
439 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
440 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
442 // dynamically allocated text input buffer
443 // always ends with zero (this is word name too)
444 static const uint32_t ufoAddrTIBx = UFO_ADDR_TEMP_BIT + 0u * 4u; // TIB
445 static const uint32_t ufoAddrINx = UFO_ADDR_TEMP_BIT + 1u * 4u; // >IN
446 static const uint32_t ufoAddrDefTIB = UFO_ADDR_TEMP_BIT + 2u * 4u; // default TIB (handle); user cannot change it
447 static const uint32_t ufoAddrBASE = UFO_ADDR_TEMP_BIT + 3u * 4u;
448 static const uint32_t ufoAddrSTATE = UFO_ADDR_TEMP_BIT + 4u * 4u;
449 static const uint32_t ufoAddrContext = UFO_ADDR_TEMP_BIT + 5u * 4u; // CONTEXT
450 static const uint32_t ufoAddrCurrent = UFO_ADDR_TEMP_BIT + 6u * 4u; // CURRENT (definitions will go there)
451 static const uint32_t ufoAddrSelf = UFO_ADDR_TEMP_BIT + 7u * 4u; // CURRENT (definitions will go there)
452 static const uint32_t ufoAddrInterNextLine = UFO_ADDR_TEMP_BIT + 8u * 4u; // (INTERPRET-NEXT-LINE)
453 static const uint32_t ufoAddrEP = UFO_ADDR_TEMP_BIT + 9u * 4u; // (EP) -- exception frame pointer
454 static const uint32_t ufoAddrUserVarUsed = UFO_ADDR_TEMP_BIT + 10u * 4u;
456 static uint32_t ufoAddrVocLink;
457 static uint32_t ufoAddrDP;
458 static uint32_t ufoAddrDPTemp;
459 static uint32_t ufoAddrNewWordFlags;
460 static uint32_t ufoAddrRedefineWarning;
461 static uint32_t ufoAddrLastXFA;
463 static uint32_t ufoForthVocId;
464 static uint32_t ufoCompilerVocId;
465 static uint32_t ufoInterpNextLineCFA;
467 // allows to redefine even protected words
468 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
469 // do not warn about ordinary words, allow others
470 #define UFO_REDEF_WARN_NONE (0)
471 // do warn (or fail on protected)
472 #define UFO_REDEF_WARN_NORMAL (1)
473 // do warn (or fail on protected) for parent dicts too
474 #define UFO_REDEF_WARN_PARENTS (2)
476 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
477 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
479 #define UFO_MAX_NESTED_INCLUDES (32)
480 typedef struct {
481 FILE *fl;
482 char *fname;
483 char *incpath;
484 char *sysincpath;
485 int fline;
486 uint32_t id; // non-zero unique id
487 } UFOFileStackEntry;
489 static UFOFileStackEntry ufoFileStack[UFO_MAX_NESTED_INCLUDES];
490 static uint32_t ufoFileStackPos; // after the last used item
492 static FILE *ufoInFile = NULL;
493 static uint32_t ufoInFileNameLen = 0;
494 static uint32_t ufoInFileNameHash = 0;
495 static char *ufoInFileName = NULL;
496 static char *ufoLastIncPath = NULL;
497 static char *ufoLastSysIncPath = NULL;
498 static int ufoInFileLine = 0;
499 static uint32_t ufoFileId = 0;
500 static uint32_t ufoLastUsedFileId = 0;
501 static int ufoLastEmitWasCR = 1;
502 static long ufoCurrIncludeLineFileOfs = 0;
504 // dynamic memory handles
505 typedef struct UHandleInfo_t {
506 uint32_t ufoHandle;
507 uint32_t typeid;
508 uint8_t *data;
509 uint32_t size;
510 uint32_t used;
511 // in free list
512 struct UHandleInfo_t *next;
513 } UfoHandle;
515 static UfoHandle *ufoHandleFreeList = NULL;
516 static UfoHandle **ufoHandles = NULL;
517 static uint32_t ufoHandlesUsed = 0;
518 static uint32_t ufoHandlesAlloted = 0;
520 #define UFO_HANDLE_FREE (~(uint32_t)0)
522 static char ufoCurrFileLine[520];
524 // for `ufoFatal()`
525 static uint32_t ufoInBacktrace = 0;
528 // ////////////////////////////////////////////////////////////////////////// //
529 static void ufoClearCondDefines (void);
531 static void ufoRunVMCFA (uint32_t cfa);
533 static void ufoBacktrace (uint32_t ip, int showDataStack);
535 static void ufoClearCondDefines (void);
537 static UfoState *ufoNewState (void);
538 static void ufoInitStateUserVars (UfoState *st, uint32_t cfa);
539 static void ufoFreeState (UfoState *st);
540 static UfoState *ufoFindState (uint32_t stid);
541 static void ufoSwitchToState (UfoState *newst);
543 __attribute__((unused)) static void ufoDumpWordHeader (const uint32_t lfa);
545 #ifndef WIN32
546 static void ufoDisableRaw (void);
547 #endif
548 static void ufoTTYRawFlush (void);
549 static int ufoIsGoodTTY (void);
551 #ifdef UFO_DEBUG_DEBUG
552 static void ufoDumpDebugImage (void);
553 #endif
556 // ////////////////////////////////////////////////////////////////////////// //
557 #define UFWORD(name_) \
558 static void ufoWord_##name_ (uint32_t mypfa)
560 #define UFCALL(name_) ufoWord_##name_(0)
561 #define UFCFA(name_) (&ufoWord_##name_)
563 // for TIB words
564 UFWORD(CPOKE_REGA_IDX);
566 // for peek and poke
567 UFWORD(PAR_HANDLE_LOAD_BYTE);
568 UFWORD(PAR_HANDLE_LOAD_WORD);
569 UFWORD(PAR_HANDLE_LOAD_CELL);
570 UFWORD(PAR_HANDLE_STORE_BYTE);
571 UFWORD(PAR_HANDLE_STORE_WORD);
572 UFWORD(PAR_HANDLE_STORE_CELL);
575 //==========================================================================
577 // ufoFlushOutput
579 //==========================================================================
580 static void ufoFlushOutput (void) {
581 ufoTTYRawFlush();
582 fflush(NULL);
586 //==========================================================================
588 // ufoSetInFileName
590 // if `reuse` is not 0, reuse/free `fname`
592 //==========================================================================
593 static void ufoSetInFileNameEx (const char *fname, int reuse) {
594 ufo_assert(fname == NULL || (fname != ufoInFileName));
595 if (fname == NULL || fname[0] == 0) {
596 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
597 ufoInFileNameLen = 0;
598 ufoInFileNameHash = 0;
599 if (reuse && fname != NULL) free((void *)fname);
600 } else {
601 const uint32_t fnlen = (uint32_t)strlen(fname);
602 const uint32_t fnhash = joaatHashBuf(fname, fnlen, 0);
603 if (ufoInFileNameLen != fnlen || ufoInFileNameHash != fnhash) {
604 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
605 if (reuse) {
606 ufoInFileName = (char *)fname;
607 } else {
608 ufoInFileName = strdup(fname);
609 if (ufoInFileName == NULL) ufoFatal("out of memory for filename info");
611 ufoInFileNameLen = fnlen;
612 ufoInFileNameHash = fnhash;
613 } else {
614 if (reuse && fname != NULL) free((void *)fname);
620 //==========================================================================
622 // ufoSetInFileName
624 //==========================================================================
625 UFO_FORCE_INLINE void ufoSetInFileName (const char *fname) {
626 ufoSetInFileNameEx(fname, 0);
630 //==========================================================================
632 // ufoSetInFileNameReuse
634 //==========================================================================
635 UFO_FORCE_INLINE void ufoSetInFileNameReuse (const char *fname) {
636 ufoSetInFileNameEx(fname, 1);
640 //==========================================================================
642 // ufoSetUserAbort
644 //==========================================================================
645 void ufoSetUserAbort (void) {
646 ufoVMAbort = 1;
650 //==========================================================================
652 // ufoAllocHandle
654 //==========================================================================
655 static UfoHandle *ufoAllocHandle (uint32_t typeid) {
656 ufo_assert(typeid != UFO_HANDLE_FREE);
657 UfoHandle *newh = ufoHandleFreeList;
658 if (newh == NULL) {
659 if (ufoHandlesUsed == ufoHandlesAlloted) {
660 uint32_t newsz = ufoHandlesAlloted + 16384;
661 // due to offsets, this is the maximum number of handles we can have
662 if (newsz > 0x1ffffU) {
663 if (ufoHandlesAlloted > 0x1ffffU) ufoFatal("too many dynamic handles");
664 newsz = 0x1ffffU + 1U;
665 ufo_assert(newsz > ufoHandlesAlloted);
667 UfoHandle **nh = realloc(ufoHandles, sizeof(ufoHandles[0]) * newsz);
668 if (nh == NULL) ufoFatal("out of memory for handle table");
669 ufoHandles = nh;
670 ufoHandlesAlloted = newsz;
672 newh = calloc(1, sizeof(UfoHandle));
673 if (newh == NULL) ufoFatal("out of memory for handle info");
674 ufoHandles[ufoHandlesUsed] = newh;
675 // setup new handle info
676 newh->ufoHandle = (ufoHandlesUsed << UFO_ADDR_HANDLE_SHIFT) | UFO_ADDR_HANDLE_BIT;
677 ufoHandlesUsed += 1;
678 } else {
679 ufo_assert(newh->typeid == UFO_HANDLE_FREE);
680 ufoHandleFreeList = newh->next;
682 // setup new handle info
683 newh->typeid = typeid;
684 newh->data = NULL;
685 newh->size = 0;
686 newh->used = 0;
687 newh->next = NULL;
688 return newh;
692 //==========================================================================
694 // ufoFreeHandle
696 //==========================================================================
697 static void ufoFreeHandle (UfoHandle *hh) {
698 if (hh != NULL) {
699 ufo_assert(hh->typeid != UFO_HANDLE_FREE);
700 if (hh->data) free(hh->data);
701 hh->typeid = UFO_HANDLE_FREE;
702 hh->data = NULL;
703 hh->size = 0;
704 hh->used = 0;
705 hh->next = ufoHandleFreeList;
706 ufoHandleFreeList = hh;
711 //==========================================================================
713 // ufoGetHandle
715 //==========================================================================
716 static UfoHandle *ufoGetHandle (uint32_t hh) {
717 UfoHandle *res;
718 if (hh != 0 && (hh & UFO_ADDR_HANDLE_BIT) != 0) {
719 hh = (hh & UFO_ADDR_HANDLE_MASK) >> UFO_ADDR_HANDLE_SHIFT;
720 if (hh < ufoHandlesUsed) {
721 res = ufoHandles[hh];
722 if (res->typeid == UFO_HANDLE_FREE) res = NULL;
723 } else {
724 res = NULL;
726 } else {
727 res = NULL;
729 return res;
733 //==========================================================================
735 // setLastIncPath
737 //==========================================================================
738 static void setLastIncPath (const char *fname, int system) {
739 if (fname == NULL || fname[0] == 0) {
740 if (system) {
741 if (ufoLastSysIncPath) free(ufoLastIncPath);
742 ufoLastSysIncPath = NULL;
743 } else {
744 if (ufoLastIncPath) free(ufoLastIncPath);
745 ufoLastIncPath = strdup(".");
747 } else {
748 char *lslash;
749 char *cpos;
750 if (system) {
751 if (ufoLastSysIncPath) free(ufoLastSysIncPath);
752 ufoLastSysIncPath = strdup(fname);
753 lslash = ufoLastSysIncPath;
754 cpos = ufoLastSysIncPath;
755 } else {
756 if (ufoLastIncPath) free(ufoLastIncPath);
757 ufoLastIncPath = strdup(fname);
758 lslash = ufoLastIncPath;
759 cpos = ufoLastIncPath;
761 while (*cpos) {
762 #ifdef WIN32
763 if (*cpos == '/' || *cpos == '\\') lslash = cpos;
764 #else
765 if (*cpos == '/') lslash = cpos;
766 #endif
767 cpos += 1;
769 *lslash = 0;
774 //==========================================================================
776 // ufoClearIncludePath
778 // required for UrAsm
780 //==========================================================================
781 void ufoClearIncludePath (void) {
782 if (ufoLastIncPath != NULL) {
783 free(ufoLastIncPath);
784 ufoLastIncPath = NULL;
786 if (ufoLastSysIncPath != NULL) {
787 free(ufoLastSysIncPath);
788 ufoLastSysIncPath = NULL;
793 //==========================================================================
795 // ufoErrorPrintFile
797 //==========================================================================
798 static void ufoErrorPrintFile (FILE *fo, const char *errwarn) {
799 if (ufoInFileName != NULL) {
800 fprintf(fo, "UFO %s at file %s, line %d: ", errwarn, ufoInFileName, ufoInFileLine);
801 } else {
802 fprintf(fo, "UFO %s somewhere in time: ", errwarn);
807 //==========================================================================
809 // ufoErrorMsgV
811 //==========================================================================
812 static void ufoErrorMsgV (const char *errwarn, const char *fmt, va_list ap) {
813 ufoFlushOutput();
814 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
815 ufoErrorPrintFile(stderr, errwarn);
816 vfprintf(stderr, fmt, ap);
817 va_end(ap);
818 fputc('\n', stderr);
819 ufoFlushOutput();
823 //==========================================================================
825 // ufoWarning
827 //==========================================================================
828 __attribute__((format(printf, 1, 2)))
829 void ufoWarning (const char *fmt, ...) {
830 va_list ap;
831 va_start(ap, fmt);
832 ufoErrorMsgV("WARNING", fmt, ap);
836 //==========================================================================
838 // ufoFatal
840 //==========================================================================
841 __attribute__((noreturn)) __attribute__((format(printf, 1, 2)))
842 void ufoFatal (const char *fmt, ...) {
843 va_list ap;
844 #ifndef WIN32
845 ufoDisableRaw();
846 #endif
847 va_start(ap, fmt);
848 ufoErrorMsgV("ERROR", fmt, ap);
849 if (!ufoInBacktrace) {
850 ufoInBacktrace = 1;
851 ufoBacktrace(ufoIP, 1);
852 ufoInBacktrace = 0;
853 } else {
854 fprintf(stderr, "DOUBLE FATAL: error in backtrace!\n");
855 abort();
857 #ifdef UFO_DEBUG_FATAL_ABORT
858 abort();
859 #endif
860 // allow restart
861 ufoInRunWord = 0;
862 ufoVMAbort = 0;
863 ufoVMStop = 0;
864 ufoFatalError();
868 // ////////////////////////////////////////////////////////////////////////// //
869 // working with the stacks
870 UFO_FORCE_INLINE void ufoPush (uint32_t v) { if (ufoSP >= UFO_DSTACK_SIZE) ufoFatal("data stack overflow"); ufoDStack[ufoSP++] = v; }
871 UFO_FORCE_INLINE void ufoDrop (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); --ufoSP; }
872 UFO_FORCE_INLINE uint32_t ufoPop (void) { if (ufoSP == 0) { ufoFatal("data stack underflow"); } return ufoDStack[--ufoSP]; }
873 UFO_FORCE_INLINE uint32_t ufoPeek (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); return ufoDStack[ufoSP-1u]; }
874 UFO_FORCE_INLINE void ufoDup (void) { if (ufoSP == 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack[ufoSP-1u]); }
875 UFO_FORCE_INLINE void ufoOver (void) { if (ufoSP < 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack[ufoSP-2u]); }
876 UFO_FORCE_INLINE void ufoSwap (void) { if (ufoSP < 2u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = t; }
877 UFO_FORCE_INLINE void ufoRot (void) { if (ufoSP < 3u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-3u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = t; }
878 UFO_FORCE_INLINE void ufoNRot (void) { if (ufoSP < 3u) ufoFatal("data stack underflow"); const uint32_t t = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-1u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-2u] = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-3u] = t; }
880 UFO_FORCE_INLINE void ufo2Dup (void) { ufoOver(); ufoOver(); }
881 UFO_FORCE_INLINE void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
882 UFO_FORCE_INLINE void ufo2Over (void) { if (ufoSP < 4u) ufoFatal("data stack underflow"); const uint32_t n0 = ufoDStack[ufoSP-4u]; const uint32_t n1 = ufoDStack[ufoSP-3u]; ufoPush(n0); ufoPush(n1); }
883 UFO_FORCE_INLINE void ufo2Swap (void) { if (ufoSP < 4u) ufoFatal("data stack underflow"); const uint32_t n0 = ufoDStack[ufoSP-4u]; const uint32_t n1 = ufoDStack[ufoSP-3u]; ufoDStack[ufoSP-4u] = ufoDStack[ufoSP-2u]; ufoDStack[ufoSP-3u] = ufoDStack[ufoSP-1u]; ufoDStack[ufoSP-2u] = n0; ufoDStack[ufoSP-1u] = n1; }
885 UFO_FORCE_INLINE void ufoRPush (uint32_t v) { if (ufoRP >= UFO_RSTACK_SIZE) ufoFatal("return stack overflow"); ufoRStack[ufoRP++] = v; }
886 UFO_FORCE_INLINE void ufoRDrop (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); --ufoRP; }
887 UFO_FORCE_INLINE uint32_t ufoRPop (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); return ufoRStack[--ufoRP]; }
888 UFO_FORCE_INLINE uint32_t ufoRPeek (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); return ufoRStack[ufoRP-1u]; }
889 UFO_FORCE_INLINE void ufoRDup (void) { if (ufoRP == 0 || ufoRP == ufoRPTop) ufoFatal("return stack underflow"); ufoPush(ufoRStack[ufoRP-1u]); }
891 UFO_FORCE_INLINE void ufoPushBool (int v) { ufoPush(v ? ufoTrueValue : 0u); }
894 //==========================================================================
896 // ufoImgEnsureSize
898 //==========================================================================
899 static void ufoImgEnsureSize (uint32_t addr) {
900 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) != 0) ufoFatal("ufoImgEnsureSize: internal error");
901 if (addr >= ufoImageSize) {
902 // 64MB should be enough for everyone!
903 if (addr >= 0x04000000U) {
904 ufoFatal("image grown too big (addr=0%08XH)", addr);
906 const uint32_t osz = ufoImageSize;
907 // grow by 1MB steps
908 const uint32_t nsz = (addr|0x000fffffU) + 1U;
909 ufo_assert(nsz > addr);
910 uint32_t *nimg = realloc(ufoImage, nsz);
911 if (nimg == NULL) {
912 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
913 ufoImageSize / 1024u / 1024u,
914 nsz / 1024u / 1024u);
916 ufoImage = nimg;
917 ufoImageSize = nsz;
918 memset((char *)ufoImage + osz, 0, (nsz - osz));
923 //==========================================================================
925 // ufoImgEnsureTemp
927 //==========================================================================
928 static void ufoImgEnsureTemp (uint32_t addr) {
929 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
930 if (addr >= ufoImageTempSize) {
931 if (addr >= 1024u * 1024u) {
932 ufoFatal("Forth segmentation fault at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
934 const uint32_t osz = ufoImageTempSize;
935 // grow by 8KB steps
936 const uint32_t nsz = (addr|0x00001fffU) + 1U;
937 uint32_t *nimg = realloc(ufoImageTemp, nsz);
938 if (nimg == NULL) {
939 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
940 ufoImageTempSize / 1024u,
941 nsz / 1024u);
943 ufoImageTemp = nimg;
944 ufoImageTempSize = nsz;
945 memset((char *)ufoImageTemp + osz, 0, (nsz - osz));
950 #ifdef UFO_FAST_MEM_ACCESS
951 //==========================================================================
953 // ufoImgPutU8
955 // fast
957 //==========================================================================
958 UFO_FORCE_INLINE void ufoImgPutU8 (uint32_t addr, const uint32_t value) {
959 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
960 if (addr >= ufoImageSize) ufoImgEnsureSize(addr);
961 *((uint8_t *)ufoImage + addr) = (uint8_t)value;
962 } else if (addr & UFO_ADDR_TEMP_BIT) {
963 addr &= UFO_ADDR_TEMP_MASK;
964 if (addr >= ufoImageTempSize) ufoImgEnsureTemp(addr);
965 *((uint8_t *)ufoImageTemp + addr) = (uint8_t)value;
966 } else {
967 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
972 //==========================================================================
974 // ufoImgPutU16
976 // fast
978 //==========================================================================
979 UFO_FORCE_INLINE void ufoImgPutU16 (uint32_t addr, const uint32_t value) {
980 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
981 if (addr + 1u >= ufoImageSize) ufoImgEnsureSize(addr + 1u);
982 *(uint16_t *)((uint8_t *)ufoImage + addr) = (uint16_t)value;
983 } else if (addr & UFO_ADDR_TEMP_BIT) {
984 addr &= UFO_ADDR_TEMP_MASK;
985 if (addr + 1u >= ufoImageTempSize) ufoImgEnsureTemp(addr + 1u);
986 *(uint16_t *)((uint8_t *)ufoImageTemp + addr) = (uint16_t)value;
987 } else {
988 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
993 //==========================================================================
995 // ufoImgPutU32
997 // fast
999 //==========================================================================
1000 UFO_FORCE_INLINE void ufoImgPutU32 (uint32_t addr, const uint32_t value) {
1001 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1002 if (addr + 3u >= ufoImageSize) ufoImgEnsureSize(addr + 3u);
1003 *(uint32_t *)((uint8_t *)ufoImage + addr) = value;
1004 } else if (addr & UFO_ADDR_TEMP_BIT) {
1005 addr &= UFO_ADDR_TEMP_MASK;
1006 if (addr + 3u >= ufoImageTempSize) ufoImgEnsureTemp(addr + 3u);
1007 *(uint32_t *)((uint8_t *)ufoImageTemp + addr) = value;
1008 } else {
1009 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1014 //==========================================================================
1016 // ufoImgGetU8
1018 // false
1020 //==========================================================================
1021 UFO_FORCE_INLINE uint32_t ufoImgGetU8 (uint32_t addr) {
1022 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1023 if (addr >= ufoImageSize) {
1024 // accessing unallocated image area is segmentation fault
1025 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
1027 return *((const uint8_t *)ufoImage + addr);
1028 } else if (addr & UFO_ADDR_TEMP_BIT) {
1029 addr &= UFO_ADDR_TEMP_MASK;
1030 if (addr >= ufoImageTempSize) {
1031 // accessing unallocated image area is segmentation fault
1032 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
1034 return *((const uint8_t *)ufoImageTemp + addr);
1035 } else {
1036 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1041 //==========================================================================
1043 // ufoImgGetU16
1045 // fast
1047 //==========================================================================
1048 UFO_FORCE_INLINE uint32_t ufoImgGetU16 (uint32_t addr) {
1049 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1050 if (addr + 1u >= ufoImageSize) {
1051 // accessing unallocated image area is segmentation fault
1052 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
1054 return *(const uint16_t *)((const uint8_t *)ufoImage + addr);
1055 } else if (addr & UFO_ADDR_TEMP_BIT) {
1056 addr &= UFO_ADDR_TEMP_MASK;
1057 if (addr + 1u >= ufoImageTempSize) {
1058 // accessing unallocated image area is segmentation fault
1059 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
1061 return *(const uint16_t *)((const uint8_t *)ufoImageTemp + addr);
1062 } else {
1063 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1068 //==========================================================================
1070 // ufoImgGetU32
1072 // fast
1074 //==========================================================================
1075 UFO_FORCE_INLINE uint32_t ufoImgGetU32 (uint32_t addr) {
1076 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1077 if (addr + 3u >= ufoImageSize) {
1078 // accessing unallocated image area is segmentation fault
1079 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr);
1081 return *(const uint32_t *)((const uint8_t *)ufoImage + addr);
1082 } else if (addr & UFO_ADDR_TEMP_BIT) {
1083 addr &= UFO_ADDR_TEMP_MASK;
1084 if (addr + 3u >= ufoImageTempSize) {
1085 // accessing unallocated image area is segmentation fault
1086 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr | UFO_ADDR_TEMP_BIT);
1088 return *(const uint32_t *)((const uint8_t *)ufoImageTemp + addr);
1089 } else {
1090 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1094 #else
1096 //==========================================================================
1098 // ufoImgPutU8
1100 // general
1102 //==========================================================================
1103 UFO_FORCE_INLINE void ufoImgPutU8 (uint32_t addr, const uint32_t value) {
1104 uint32_t *imgptr;
1105 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1106 if (addr >= ufoImageSize) ufoImgEnsureSize(addr);
1107 imgptr = &ufoImage[addr/4u];
1108 } else if (addr & UFO_ADDR_TEMP_BIT) {
1109 addr &= UFO_ADDR_TEMP_MASK;
1110 if (addr >= ufoImageTempSize) ufoImgEnsureTemp(addr);
1111 imgptr = &ufoImageTemp[addr/4u];
1112 } else {
1113 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1115 const uint8_t val = (uint8_t)value;
1116 memcpy((uint8_t *)imgptr + (addr&3), &val, 1);
1120 //==========================================================================
1122 // ufoImgPutU16
1124 // general
1126 //==========================================================================
1127 UFO_FORCE_INLINE void ufoImgPutU16 (uint32_t addr, const uint32_t value) {
1128 ufoImgPutU8(addr, value&0xffU);
1129 ufoImgPutU8(addr + 1u, (value>>8)&0xffU);
1133 //==========================================================================
1135 // ufoImgPutU32
1137 // general
1139 //==========================================================================
1140 UFO_FORCE_INLINE void ufoImgPutU32 (uint32_t addr, const uint32_t value) {
1141 ufoImgPutU16(addr, value&0xffffU);
1142 ufoImgPutU16(addr + 2u, (value>>16)&0xffffU);
1146 //==========================================================================
1148 // ufoImgGetU8
1150 // general
1152 //==========================================================================
1153 UFO_FORCE_INLINE uint32_t ufoImgGetU8 (uint32_t addr) {
1154 uint32_t *imgptr;
1155 if ((addr & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
1156 if (addr >= ufoImageSize) return 0;
1157 imgptr = &ufoImage[addr/4u];
1158 } else if (addr & UFO_ADDR_TEMP_BIT) {
1159 addr &= UFO_ADDR_TEMP_MASK;
1160 if (addr >= ufoImageTempSize) return 0;
1161 imgptr = &ufoImageTemp[addr/4u];
1162 } else {
1163 ufoFatal("Forth segmentation fault at address 0x%08X", addr);
1165 uint8_t val;
1166 memcpy(&val, (uint8_t *)imgptr + (addr&3), 1);
1167 return (uint32_t)val;
1171 //==========================================================================
1173 // ufoImgGetU16
1175 // general
1177 //==========================================================================
1178 UFO_FORCE_INLINE uint32_t ufoImgGetU16 (uint32_t addr) {
1179 return ufoImgGetU8(addr) | (ufoImgGetU8(addr + 1u) << 8);
1183 //==========================================================================
1185 // ufoImgGetU32
1187 // general
1189 //==========================================================================
1190 UFO_FORCE_INLINE uint32_t ufoImgGetU32 (uint32_t addr) {
1191 return ufoImgGetU16(addr) | (ufoImgGetU16(addr + 2u) << 16);
1193 #endif
1196 //==========================================================================
1198 // ufoEnsureDebugSize
1200 //==========================================================================
1201 UFO_DISABLE_INLINE void ufoEnsureDebugSize (uint32_t sdelta) {
1202 ufo_assert(sdelta != 0);
1203 if (ufoDebugImageSize != 0) {
1204 if (ufoDebugImageUsed + sdelta >= 0x40000000U) ufoFatal("debug info too big");
1205 if (ufoDebugImageUsed + sdelta > ufoDebugImageSize) {
1206 // grow by 32KB, this should be more than enough
1207 const uint32_t newsz = ((ufoDebugImageUsed + sdelta) | 0x7fffU) + 1u;
1208 uint8_t *ndb = realloc(ufoDebugImage, newsz);
1209 if (ndb == NULL) ufoFatal("out of memory for debug info");
1210 ufoDebugImage = ndb;
1211 ufoDebugImageSize = newsz;
1213 } else {
1214 // initial allocation: 32KB, quite a lot
1215 ufo_assert(ufoDebugImage == NULL);
1216 ufo_assert(ufoDebugImageUsed == 0);
1217 ufoDebugImageSize = 1024 * 32;
1218 ufoDebugImage = malloc(ufoDebugImageSize);
1219 if (ufoDebugImage == NULL) ufoFatal("out of memory for debug info");
1224 #define UFO_DBG_PUT_U4(val_) do { \
1225 const uint32_t vv_ = (val_); \
1226 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1227 ufoDebugImageUsed += 4u; \
1228 } while (0)
1232 debug info header:
1233 dd lastFileInfoOfs
1234 ...first line info header...
1235 line info header (or reset):
1236 db 0 ; zero line delta
1237 dw followFileInfoSize ; either it, or 0 if reused
1238 dd fileInfoOfs ; present only if reused
1239 lines:
1240 dv lineDelta
1241 dv pcBytes
1243 file info record:
1244 dd prevFileInfoOfs
1245 dd fileNameHash
1246 dd nameLen ; without terminating 0
1247 ...name... (0-terminated)
1249 we will never compare file names: length and hash should provide
1250 good enough unique identifier.
1252 static uint8_t *ufoDebugImage = NULL;
1253 static uint32_t ufoDebugImageUsed = 0; // in bytes
1254 static uint32_t ufoDebugImageSize = 0; // in bytes
1255 static uint32_t ufoDebugFileNameHash = 0; // current file name hash
1256 static uint32_t ufoDebugFileNameLen = 0; // current file name length
1257 static uint32_t ufoDebugCurrDP = 0;
1261 //==========================================================================
1263 // ufoSkipDebugVarInt
1265 //==========================================================================
1266 static __attribute__((unused)) uint32_t ufoSkipDebugVarInt (uint32_t ofs) {
1267 uint8_t byte;
1268 do {
1269 if (ofs >= ufoDebugImageUsed) ufoFatal("invalid debug data");
1270 byte = ufoDebugImage[ofs]; ofs += 1u;
1271 } while (byte >= 0x80);
1272 return ofs;
1276 //==========================================================================
1278 // ufoCalcDebugVarIntSize
1280 //==========================================================================
1281 UFO_FORCE_INLINE uint8_t ufoCalcDebugVarIntSize (uint32_t v) {
1282 uint8_t count = 0;
1283 do {
1284 count += 1u;
1285 v >>= 7;
1286 } while (v != 0);
1287 return count;
1291 //==========================================================================
1293 // ufoGetDebugVarInt
1295 //==========================================================================
1296 static __attribute__((unused)) uint32_t ufoGetDebugVarInt (uint32_t ofs) {
1297 uint32_t v = 0;
1298 uint8_t shift = 0;
1299 uint8_t byte;
1300 do {
1301 if (ofs >= ufoDebugImageUsed) ufoFatal("invalid debug data");
1302 byte = ufoDebugImage[ofs];
1303 v |= (uint32_t)(byte & 0x7f) << shift;
1304 if (byte >= 0x80) {
1305 shift += 7;
1306 ofs += 1u;
1308 } while (byte >= 0x80);
1309 return v;
1313 //==========================================================================
1315 // ufoPutDebugVarInt
1317 //==========================================================================
1318 UFO_FORCE_INLINE void ufoPutDebugVarInt (uint32_t v) {
1319 ufoEnsureDebugSize(5u); // maximum size
1320 do {
1321 if (v >= 0x80) {
1322 ufoDebugImage[ufoDebugImageUsed] = (uint8_t)(v | 0x80u);
1323 } else {
1324 ufoDebugImage[ufoDebugImageUsed] = (uint8_t)v;
1326 ufoDebugImageUsed += 1;
1327 v >>= 7;
1328 } while (v != 0);
1332 #ifdef UFO_DEBUG_DEBUG
1333 //==========================================================================
1335 // ufoDumpDebugInfo
1337 //==========================================================================
1338 static void ufoDumpDebugImage (void) {
1339 #if 0
1340 uint32_t dbgpos = 4u; // first line header info
1341 uint32_t lastline = 0;
1342 uint32_t lastdp = 0;
1343 while (dbgpos < ufoDebugImageUsed) {
1344 if (ufoDebugImage[dbgpos] == 0) {
1345 // new file info
1346 dbgpos += 1u; // skip flag
1347 const uint32_t fhdrSize = *(const uint16_t *)(ufoDebugImage + dbgpos); dbgpos += 2u;
1348 lastdp = ufoGetDebugVarInt(dbgpos);
1349 dbgpos = ufoSkipDebugVarInt(dbgpos);
1350 if (fhdrSize == 0) {
1351 // reused
1352 const uint32_t infoOfs = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1353 fprintf(stderr, "*** OLD FILE: %s\n", (const char *)(ufoDebugImage + infoOfs + 3u * 4u));
1354 fprintf(stderr, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage + infoOfs))[2]);
1355 fprintf(stderr, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage + infoOfs))[1]);
1356 } else {
1357 // new
1358 fprintf(stderr, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage + dbgpos + 3u * 4u));
1359 fprintf(stderr, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage + dbgpos))[2]);
1360 fprintf(stderr, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage + dbgpos))[1]);
1362 dbgpos += fhdrSize;
1363 fprintf(stderr, "LINES-OFS: 0x%08x (hsz: %u -- 0x%08x)\n", dbgpos, fhdrSize, fhdrSize);
1364 lastline = ~(uint32_t)0;
1365 } else {
1366 const uint32_t ln = ufoGetDebugVarInt(dbgpos);
1367 dbgpos = ufoSkipDebugVarInt(dbgpos);
1368 ufo_assert(ln != 0);
1369 lastline += ln;
1370 const uint32_t edp = ufoGetDebugVarInt(dbgpos);
1371 dbgpos = ufoSkipDebugVarInt(dbgpos);
1372 lastdp += edp;
1373 fprintf(stderr, " line %6u: edp=%u\n", lastline, lastdp);
1376 #endif
1378 #endif
1381 //==========================================================================
1383 // ufoRecordDebugCheckFile
1385 // if we moved to the new file:
1386 // put "line info header"
1387 // put new file info (or reuse old)
1389 //==========================================================================
1390 UFO_FORCE_INLINE void ufoRecordDebugCheckFile (void) {
1391 if (ufoDebugImageUsed == 0 ||
1392 ufoDebugFileNameLen != ufoInFileNameLen ||
1393 ufoDebugFileNameHash != ufoInFileNameHash)
1395 // new file record (or reuse old one)
1396 const int initial = (ufoDebugImageUsed == 0);
1397 uint32_t fileRec = 0;
1398 // try to find and old one
1399 if (!initial) {
1400 fileRec = *(const uint32_t *)ufoDebugImage;
1401 #if 0
1402 fprintf(stderr, "*** NEW-FILE(%u): 0x%08x: <%s> (frec=0x%08x)\n", ufoInFileNameLen,
1403 ufoInFileNameHash, ufoInFileName, fileRec);
1404 #endif
1405 while (fileRec != 0 &&
1406 (ufoInFileNameLen != ((const uint32_t *)(ufoDebugImage + fileRec))[1] ||
1407 ufoInFileNameHash != ((const uint32_t *)(ufoDebugImage + fileRec))[2]))
1409 #if 0
1410 fprintf(stderr, "*** FRCHECK: 0x%08x\n", fileRec);
1411 fprintf(stderr, " FILE NAME: %s\n", (const char *)(ufoDebugImage + fileRec + 3u * 4u));
1412 fprintf(stderr, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage + fileRec))[2]);
1413 fprintf(stderr, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage + fileRec))[1]);
1414 fprintf(stderr, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage + fileRec));
1415 #endif
1416 fileRec = *(const uint32_t *)(ufoDebugImage + fileRec);
1418 #if 0
1419 fprintf(stderr, "*** FRCHECK-DONE: 0x%08x\n", fileRec);
1420 if (fileRec != 0) {
1421 fprintf(stderr, " FILE NAME: %s\n", (const char *)(ufoDebugImage + fileRec + 3u * 4u));
1422 fprintf(stderr, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage + fileRec))[2]);
1423 fprintf(stderr, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage + fileRec))[1]);
1424 fprintf(stderr, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage + fileRec));
1426 #endif
1427 } else {
1428 ufoEnsureDebugSize(8u);
1429 *(uint32_t *)ufoDebugImage = 0;
1431 // write "line info header"
1432 if (fileRec != 0) {
1433 ufoEnsureDebugSize(32u);
1434 ufoDebugImage[ufoDebugImageUsed] = 0; ufoDebugImageUsed += 1u; // header flag (0 delta)
1435 // file record size: 0 (reused)
1436 *((uint16_t *)(ufoDebugImage + ufoDebugImageUsed)) = 0; ufoDebugImageUsed += 2u;
1437 // put last DP
1438 ufoPutDebugVarInt(ufoDebugCurrDP);
1439 // file info offset
1440 UFO_DBG_PUT_U4(fileRec);
1441 } else {
1442 // name, trailing 0 byte, 3 dword fields
1443 const uint32_t finfoSize = ufoInFileNameLen + 1u + 3u * 4u;
1444 ufo_assert(finfoSize < 65536u);
1445 ufoEnsureDebugSize(finfoSize + 32u);
1446 if (initial) {
1447 *(uint32_t *)ufoDebugImage = 0;
1448 ufoDebugImageUsed = 4;
1450 ufoDebugImage[ufoDebugImageUsed] = 0; ufoDebugImageUsed += 1u; // header flag (0 delta)
1451 // file record size
1452 *((uint16_t *)(ufoDebugImage + ufoDebugImageUsed)) = (uint16_t)finfoSize; ufoDebugImageUsed += 2u;
1453 // put last DP
1454 ufoPutDebugVarInt(ufoDebugCurrDP);
1455 // file record follows
1456 // fix file info offsets
1457 uint32_t lastOfs = *(const uint32_t *)ufoDebugImage;
1458 *(uint32_t *)ufoDebugImage = ufoDebugImageUsed;
1459 UFO_DBG_PUT_U4(lastOfs);
1460 // save file info hash
1461 UFO_DBG_PUT_U4(ufoInFileNameHash);
1462 // save file info length
1463 UFO_DBG_PUT_U4(ufoInFileNameLen);
1464 // save file name
1465 if (ufoInFileNameLen != 0) {
1466 memcpy(ufoDebugImage + ufoDebugImageUsed, ufoInFileName, ufoInFileNameLen + 1u);
1467 ufoDebugImageUsed += ufoInFileNameLen + 1u;
1468 } else {
1469 ufoDebugImage[ufoDebugImageUsed] = 0; ufoDebugImageUsed += 1u;
1472 ufoDebugFileNameLen = ufoInFileNameLen;
1473 ufoDebugFileNameHash = ufoInFileNameHash;
1474 ufoDebugLastLine = ~(uint32_t)0;
1475 ufoDebugLastLinePCOfs = 0;
1476 ufoDebugLastLineDP = ufoDebugCurrDP;
1481 //==========================================================================
1483 // ufoRecordDebugRecordLine
1485 //==========================================================================
1486 UFO_FORCE_INLINE void ufoRecordDebugRecordLine (uint32_t line, uint32_t newhere) {
1487 if (line == ufoDebugLastLine) {
1488 ufo_assert(ufoDebugLastLinePCOfs != 0);
1489 ufoDebugImageUsed = ufoDebugLastLinePCOfs;
1490 } else {
1491 #if 0
1492 fprintf(stderr, "FL-NEW-LINE(0x%08x): <%s>; new line: %u (old: %u)\n",
1493 ufoDebugImageUsed,
1494 ufoInFileName, line, ufoDebugLastLine);
1495 #endif
1496 ufoPutDebugVarInt(line - ufoDebugLastLine);
1497 ufoDebugLastLinePCOfs = ufoDebugImageUsed;
1498 ufoDebugLastLine = line;
1499 ufoDebugLastLineDP = ufoDebugCurrDP;
1501 ufoPutDebugVarInt(newhere - ufoDebugLastLineDP);
1502 ufoDebugCurrDP = newhere;
1506 //==========================================================================
1508 // ufoRecordDebug
1510 //==========================================================================
1511 UFO_DISABLE_INLINE void ufoRecordDebug (uint32_t newhere) {
1512 if (newhere > ufoDebugCurrDP) {
1513 uint32_t ln = (uint32_t)ufoInFileLine;
1514 if (ln == ~(uint32_t)0) ln = 0;
1515 #if 0
1516 fprintf(stderr, "FL: <%s>; line: %d\n", ufoInFileName, ufoInFileLine);
1517 #endif
1518 ufoRecordDebugCheckFile();
1519 ufoRecordDebugRecordLine(ln, newhere);
1524 //==========================================================================
1526 // ufoGetWordEndAddrYFA
1528 //==========================================================================
1529 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa) {
1530 if (yfa > 8u) {
1531 const uint32_t oyfa = yfa;
1532 yfa = ufoImgGetU32(yfa);
1533 if (yfa == 0) {
1534 if ((oyfa & UFO_ADDR_TEMP_BIT) == 0) {
1535 yfa = UFO_GET_DP();
1536 if ((yfa & UFO_ADDR_TEMP_BIT) != 0) {
1537 yfa = UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa)));
1539 } else {
1540 yfa = UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa)));
1542 } else {
1543 yfa = UFO_YFA_TO_WST(yfa);
1545 } else {
1546 yfa = 0;
1548 return yfa;
1552 //==========================================================================
1554 // ufoGetWordEndAddr
1556 //==========================================================================
1557 static uint32_t ufoGetWordEndAddr (const uint32_t cfa) {
1558 if (cfa != 0) {
1559 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa)));
1560 } else {
1561 return 0;
1566 //==========================================================================
1568 // ufoFindWordForIP
1570 // return NFA or 0
1572 // WARNING: this is SLOW!
1574 //==========================================================================
1575 static uint32_t ufoFindWordForIP (const uint32_t ip) {
1576 uint32_t res = 0;
1577 if (ip != 0) {
1578 //fprintf(stderr, "ufoFindWordForIP:000: ip=0x%08x\n", ip);
1579 // iterate over all words
1580 uint32_t xfa = ufoImgGetU32(ufoAddrLastXFA);
1581 //fprintf(stderr, "ufoFindWordForIP:001: xfa=0x%08x\n", xfa);
1582 if (xfa != 0) {
1583 while (res == 0 && xfa != 0) {
1584 const uint32_t yfa = UFO_XFA_TO_YFA(xfa);
1585 const uint32_t wst = UFO_YFA_TO_WST(yfa);
1586 //fprintf(stderr, "ufoFindWordForIP:002: yfa=0x%08x; wst=0x%08x\n", yfa, wst);
1587 const uint32_t wend = ufoGetWordEndAddrYFA(yfa);
1588 if (ip >= wst && ip < wend) {
1589 res = UFO_YFA_TO_NFA(yfa);
1590 } else {
1591 xfa = ufoImgGetU32(xfa);
1596 return res;
1600 //==========================================================================
1602 // ufoFindFileForIP
1604 // return file name or `NULL`
1606 // WARNING: this is SLOW!
1608 //==========================================================================
1609 static const char *ufoFindFileForIP (uint32_t ip, uint32_t *line,
1610 uint32_t *nlen, uint32_t *nhash)
1612 if (ip != 0 && ufoDebugImageUsed != 0) {
1613 const char *filename = NULL;
1614 uint32_t dbgpos = 4u; // first line header info
1615 uint32_t lastline = 0;
1616 uint32_t lastdp = 0;
1617 uint32_t namelen = 0;
1618 uint32_t namehash = 0;
1619 while (dbgpos < ufoDebugImageUsed) {
1620 if (ufoDebugImage[dbgpos] == 0) {
1621 // new file info
1622 dbgpos += 1u; // skip flag
1623 const uint32_t fhdrSize = *(const uint16_t *)(ufoDebugImage + dbgpos); dbgpos += 2u;
1624 lastdp = ufoGetDebugVarInt(dbgpos);
1625 dbgpos = ufoSkipDebugVarInt(dbgpos);
1626 uint32_t infoOfs;
1627 if (fhdrSize == 0) {
1628 // reused
1629 infoOfs = *(const uint32_t *)(ufoDebugImage + dbgpos); dbgpos += 4u;
1630 } else {
1631 // new
1632 infoOfs = dbgpos;
1634 filename = (const char *)(ufoDebugImage + infoOfs + 3u * 4u);
1635 namelen = ((const uint32_t *)(ufoDebugImage + infoOfs))[2];
1636 namehash = ((const uint32_t *)(ufoDebugImage + infoOfs))[1];
1637 if (filename[0] == 0) filename = NULL;
1638 dbgpos += fhdrSize;
1639 lastline = ~(uint32_t)0;
1640 } else {
1641 const uint32_t ln = ufoGetDebugVarInt(dbgpos);
1642 dbgpos = ufoSkipDebugVarInt(dbgpos);
1643 ufo_assert(ln != 0);
1644 lastline += ln;
1645 const uint32_t edp = ufoGetDebugVarInt(dbgpos);
1646 dbgpos = ufoSkipDebugVarInt(dbgpos);
1647 if (ip >= lastdp && ip < lastdp + edp) {
1648 if (line) *line = lastline;
1649 if (nlen) *nlen = namelen;
1650 if (nhash) *nhash = namehash;
1651 return filename;
1653 lastdp += edp;
1657 if (line) *line = 0;
1658 if (nlen) *nlen = 0;
1659 if (nhash) *nlen = 0;
1660 return NULL;
1664 //==========================================================================
1666 // ufoBumpDP
1668 //==========================================================================
1669 UFO_FORCE_INLINE void ufoBumpDP (uint32_t delta) {
1670 uint32_t dp = ufoImgGetU32(ufoAddrDPTemp);
1671 if (dp == 0) {
1672 dp = ufoImgGetU32(ufoAddrDP);
1673 if ((dp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(dp + delta);
1674 dp += delta;
1675 ufoImgPutU32(ufoAddrDP, dp);
1676 } else {
1677 dp = ufoImgGetU32(ufoAddrDPTemp);
1678 if ((dp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(dp + delta);
1679 dp += delta;
1680 ufoImgPutU32(ufoAddrDPTemp, dp);
1685 //==========================================================================
1687 // ufoImgEmitU8
1689 //==========================================================================
1690 UFO_FORCE_INLINE void ufoImgEmitU8 (uint32_t value) {
1691 ufoImgPutU8(UFO_GET_DP(), value);
1692 ufoBumpDP(1);
1696 //==========================================================================
1698 // ufoImgEmitU32
1700 //==========================================================================
1701 UFO_FORCE_INLINE void ufoImgEmitU32 (uint32_t value) {
1702 ufoImgPutU32(UFO_GET_DP(), value);
1703 ufoBumpDP(4);
1707 #ifdef UFO_FAST_MEM_ACCESS
1709 //==========================================================================
1711 // ufoImgEmitU32_NoInline
1713 // false
1715 //==========================================================================
1716 UFO_FORCE_INLINE void ufoImgEmitU32_NoInline (uint32_t value) {
1717 ufoImgPutU32(UFO_GET_DP(), value);
1718 ufoBumpDP(4);
1721 #else
1723 //==========================================================================
1725 // ufoImgEmitU32_NoInline
1727 // general
1729 //==========================================================================
1730 UFO_DISABLE_INLINE void ufoImgEmitU32_NoInline (uint32_t value) {
1731 ufoImgPutU32(UFO_GET_DP(), value);
1732 ufoBumpDP(4);
1735 #endif
1738 //==========================================================================
1740 // ufoImgGetU8Ext
1742 // this understands handle addresses
1744 //==========================================================================
1745 UFO_FORCE_INLINE uint32_t ufoImgGetU8Ext (uint32_t addr) {
1746 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
1747 return ufoImgGetU8(addr);
1748 } else {
1749 ufoPush(0);
1750 ufoPush(addr);
1751 UFCALL(PAR_HANDLE_LOAD_BYTE);
1752 return ufoPop();
1757 //==========================================================================
1759 // ufoImgPutU8Ext
1761 // this understands handle addresses
1763 //==========================================================================
1764 UFO_FORCE_INLINE void ufoImgPutU8Ext (uint32_t addr, uint32_t value) {
1765 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
1766 ufoImgPutU8(addr, value);
1767 } else {
1768 ufoPush(value);
1769 ufoPush(0);
1770 ufoPush(addr);
1771 UFCALL(PAR_HANDLE_STORE_BYTE);
1776 //==========================================================================
1778 // ufoImgEmitAlign
1780 //==========================================================================
1781 UFO_FORCE_INLINE void ufoImgEmitAlign (void) {
1782 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1786 //==========================================================================
1788 // ufoResetTib
1790 //==========================================================================
1791 UFO_FORCE_INLINE void ufoResetTib (void) {
1792 uint32_t defTIB = ufoImgGetU32(ufoAddrDefTIB);
1793 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1794 if (defTIB == 0) {
1795 // create new TIB handle
1796 UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
1797 defTIB = tibh->ufoHandle;
1798 ufoImgPutU32(ufoAddrDefTIB, defTIB);
1800 if ((defTIB & UFO_ADDR_HANDLE_BIT) != 0) {
1801 UfoHandle *hh = ufoGetHandle(defTIB);
1802 if (hh == NULL) ufoFatal("default TIB is not allocated");
1803 if (hh->size == 0) {
1804 ufo_assert(hh->data == NULL);
1805 hh->data = calloc(1, UFO_ADDR_HANDLE_OFS_MASK + 1);
1806 if (hh->data == NULL) ufoFatal("out of memory for default TIB");
1807 hh->size = UFO_ADDR_HANDLE_OFS_MASK + 1;
1810 const uint32_t oldA = ufoRegA;
1811 ufoImgPutU32(ufoAddrTIBx, defTIB);
1812 ufoImgPutU32(ufoAddrINx, 0);
1813 ufoRegA = defTIB;
1814 ufoPush(0); // value
1815 ufoPush(0); // offset
1816 UFCALL(CPOKE_REGA_IDX);
1817 ufoRegA = oldA;
1821 //==========================================================================
1823 // ufoTibEnsureSize
1825 //==========================================================================
1826 UFO_DISABLE_INLINE void ufoTibEnsureSize (uint32_t size) {
1827 if (size > 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1828 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1829 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1830 if ((tib & UFO_ADDR_HANDLE_BIT) != 0) {
1831 UfoHandle *hh = ufoGetHandle(tib);
1832 if (hh == NULL) {
1833 ufoFatal("cannot resize TIB, TIB is not a handle");
1835 if (hh->size < size) {
1836 const uint32_t newsz = (size | 0xfffU) + 1u;
1837 uint8_t *nx = realloc(hh->data, newsz);
1838 if (nx == NULL) ufoFatal("out of memory for restored TIB");
1839 hh->data = nx;
1840 hh->size = newsz;
1843 #if 0
1844 else {
1845 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib);
1847 #endif
1851 //==========================================================================
1853 // ufoTibGetSize
1855 //==========================================================================
1857 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1858 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1859 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1860 ufoFatal("cannot query TIB, TIB is not a handle");
1862 UfoHandle *hh = ufoGetHandle(tib);
1863 if (hh == NULL) {
1864 ufoFatal("cannot query TIB, TIB is not a handle");
1866 return hh->size;
1871 //==========================================================================
1873 // ufoTibPeekCh
1875 //==========================================================================
1876 UFO_FORCE_INLINE uint8_t ufoTibPeekCh (void) {
1877 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx));
1881 //==========================================================================
1883 // ufoTibPeekChOfs
1885 //==========================================================================
1886 UFO_FORCE_INLINE uint8_t ufoTibPeekChOfs (uint32_t ofs) {
1887 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1888 if (ofs <= UFO_ADDR_HANDLE_OFS_MASK || (tib & UFO_ADDR_HANDLE_BIT) == 0) {
1889 return (uint8_t)ufoImgGetU8Ext(tib + ufoImgGetU32(ufoAddrINx) + ofs);
1890 } else {
1891 return 0;
1896 //==========================================================================
1898 // ufoTibPokeChOfs
1900 //==========================================================================
1901 UFO_DISABLE_INLINE void ufoTibPokeChOfs (uint8_t ch, uint32_t ofs) {
1902 const uint32_t oldA = ufoRegA;
1903 ufoRegA = ufoImgGetU32(ufoAddrTIBx);
1904 ufoPush(ch);
1905 ufoPush(ufoImgGetU32(ufoAddrINx) + ofs);
1906 UFCALL(CPOKE_REGA_IDX);
1907 ufoRegA = oldA;
1911 //==========================================================================
1913 // ufoTibGetCh
1915 //==========================================================================
1916 UFO_FORCE_INLINE uint8_t ufoTibGetCh (void) {
1917 const uint8_t ch = ufoTibPeekCh();
1918 if (ch) ufoImgPutU32(ufoAddrINx, ufoImgGetU32(ufoAddrINx) + 1u);
1919 return ch;
1923 //==========================================================================
1925 // ufoTibSkipCh
1927 //==========================================================================
1928 UFO_FORCE_INLINE void ufoTibSkipCh (void) {
1929 (void)ufoTibGetCh();
1933 // ////////////////////////////////////////////////////////////////////////// //
1934 // native CFA implementations
1937 //==========================================================================
1939 // ufoDoForth
1941 //==========================================================================
1942 static void ufoDoForth (uint32_t pfa) {
1943 ufoRPush(ufoIP);
1944 ufoIP = pfa;
1948 //==========================================================================
1950 // ufoDoVariable
1952 //==========================================================================
1953 static void ufoDoVariable (uint32_t pfa) {
1954 ufoPush(pfa);
1958 //==========================================================================
1960 // ufoDoUserVariable
1962 //==========================================================================
1963 static void ufoDoUserVariable (uint32_t pfa) {
1964 ufoPush(ufoImgGetU32(pfa));
1968 //==========================================================================
1970 // ufoDoValue
1972 //==========================================================================
1973 static void ufoDoValue (uint32_t pfa) {
1974 ufoPush(ufoImgGetU32(pfa));
1978 //==========================================================================
1980 // ufoDoConst
1982 //==========================================================================
1983 static void ufoDoConst (uint32_t pfa) {
1984 ufoPush(ufoImgGetU32(pfa));
1988 //==========================================================================
1990 // ufoDoDefer
1992 //==========================================================================
1993 static void ufoDoDefer (uint32_t pfa) {
1994 const uint32_t cfa = ufoImgGetU32(pfa);
1995 if (cfa != 0) {
1996 ufoRPush(cfa);
1997 ufoVMRPopCFA = 1;
2002 //==========================================================================
2004 // ufoDoVoc
2006 //==========================================================================
2007 static void ufoDoVoc (uint32_t pfa) {
2008 ufoImgPutU32(ufoAddrContext, ufoImgGetU32(pfa));
2012 //==========================================================================
2014 // ufoDoCreate
2016 //==========================================================================
2017 static void ufoDoCreate (uint32_t pfa) {
2018 ufoPush(pfa);
2022 //==========================================================================
2024 // ufoPushInFile
2026 // this also increments last used file id
2028 //==========================================================================
2029 static void ufoPushInFile (void) {
2030 if (ufoFileStackPos >= UFO_MAX_NESTED_INCLUDES) ufoFatal("too many includes");
2031 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
2032 stk->fl = ufoInFile;
2033 stk->fname = ufoInFileName;
2034 stk->fline = ufoInFileLine;
2035 stk->id = ufoFileId;
2036 stk->incpath = (ufoLastIncPath ? strdup(ufoLastIncPath) : NULL);
2037 stk->sysincpath = (ufoLastSysIncPath ? strdup(ufoLastSysIncPath) : NULL);
2038 ufoFileStackPos += 1;
2039 ufoInFile = NULL;
2040 ufoInFileName = NULL; ufoInFileNameLen = 0; ufoInFileNameHash = 0;
2041 ufoInFileLine = 0;
2042 ufoLastUsedFileId += 1;
2043 ufo_assert(ufoLastUsedFileId != 0); // just in case ;-)
2044 //ufoLastIncPath = NULL;
2048 //==========================================================================
2050 // ufoWipeIncludeStack
2052 //==========================================================================
2053 static void ufoWipeIncludeStack (void) {
2054 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
2055 if (ufoInFile) { fclose(ufoInFile); ufoInFile = NULL; }
2056 if (ufoLastIncPath) { free(ufoLastIncPath); ufoLastIncPath = NULL; }
2057 if (ufoLastSysIncPath) { free(ufoLastSysIncPath); ufoLastSysIncPath = NULL; }
2058 while (ufoFileStackPos != 0) {
2059 ufoFileStackPos -= 1;
2060 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
2061 if (stk->fl) fclose(stk->fl);
2062 if (stk->fname) free(stk->fname);
2063 if (stk->incpath) free(stk->incpath);
2068 //==========================================================================
2070 // ufoPopInFile
2072 //==========================================================================
2073 static void ufoPopInFile (void) {
2074 if (ufoFileStackPos == 0) ufoFatal("trying to pop include from empty stack");
2075 if (ufoInFileName) { free(ufoInFileName); ufoInFileName = NULL; }
2076 if (ufoInFile) { fclose(ufoInFile); ufoInFile = NULL; }
2077 if (ufoLastIncPath) { free(ufoLastIncPath); ufoLastIncPath = NULL; }
2078 if (ufoLastSysIncPath) { free(ufoLastSysIncPath); ufoLastSysIncPath = NULL; }
2079 ufoFileStackPos -= 1;
2080 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos];
2081 ufoInFile = stk->fl;
2082 ufoSetInFileNameReuse(stk->fname);
2083 ufoInFileLine = stk->fline;
2084 ufoLastIncPath = stk->incpath;
2085 ufoLastSysIncPath = stk->sysincpath;
2086 ufoFileId = stk->id;
2087 ufoResetTib();
2088 #ifdef UFO_DEBUG_INCLUDE
2089 if (ufoInFileName == NULL) {
2090 fprintf(stderr, "INC-POP: no more files.\n");
2091 } else {
2092 fprintf(stderr, "INC-POP: fname: %s\n", ufoInFileName);
2094 #endif
2098 //==========================================================================
2100 // ufoDeinit
2102 //==========================================================================
2103 void ufoDeinit (void) {
2104 #ifdef UFO_DEBUG_WRITE_MAIN_IMAGE
2106 FILE *fo = fopen("zufo_main.img", "w");
2107 uint32_t dpTemp = ufoImgGetU32(ufoAddrDPTemp);
2108 uint32_t dpMain = ufoImgGetU32(ufoAddrDP);
2109 if ((dpMain & UFO_ADDR_SPECIAL_BITS_MASK) != 0) dpMain = ufoImageSize;
2110 if (dpTemp != 0 && (dpTemp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
2111 if (dpTemp > dpMain) dpMain = dpTemp;
2113 fwrite(ufoImage, dpMain, 1, fo);
2114 fclose(fo);
2116 #endif
2118 #ifdef UFO_DEBUG_WRITE_DEBUG_IMAGE
2120 FILE *fo = fopen("zufo_debug.img", "w");
2121 fwrite(ufoDebugImage, ufoDebugImageUsed, 1, fo);
2122 fclose(fo);
2124 #endif
2126 #ifdef UFO_DEBUG_DEBUG
2128 uint32_t dpTemp = ufoImgGetU32(ufoAddrDPTemp);
2129 uint32_t dpMain = ufoImgGetU32(ufoAddrDP);
2130 if ((dpMain & UFO_ADDR_SPECIAL_BITS_MASK) != 0) dpMain = ufoImageSize;
2131 if (dpTemp != 0 && (dpTemp & UFO_ADDR_SPECIAL_BITS_MASK) == 0) {
2132 if (dpTemp > dpMain) dpMain = dpTemp;
2134 fprintf(stderr, "UFO: image used: %u; size: %u\n",
2135 dpMain, ufoImageSize);
2136 fprintf(stderr, "UFO: debug image used: %u; size: %u\n",
2137 ufoDebugImageUsed, ufoDebugImageSize);
2138 ufoDumpDebugImage();
2140 #endif
2142 // free all states
2143 ufoCurrState = NULL;
2144 ufoYieldedState = NULL;
2145 ufoDebuggerState = NULL;
2146 for (uint32_t fidx = 0; fidx < (uint32_t)(UFO_MAX_STATES/32); fidx += 1u) {
2147 uint32_t bmp = ufoStateUsedBitmap[fidx];
2148 if (bmp != 0) {
2149 uint32_t stid = fidx * 32u;
2150 while (bmp != 0) {
2151 if ((bmp & 0x01) != 0) ufoFreeState(ufoStateMap[stid]);
2152 stid += 1u; bmp >>= 1;
2157 free(ufoDebugImage);
2158 ufoDebugImage = NULL;
2159 ufoDebugImageUsed = 0;
2160 ufoDebugImageSize = 0;
2161 ufoDebugFileNameHash = 0;
2162 ufoDebugFileNameLen = 0;
2163 ufoDebugLastLine = 0;
2164 ufoDebugLastLinePCOfs = 0;
2165 ufoDebugLastLineDP = 0;
2166 ufoDebugCurrDP = 0;
2168 ufoInBacktrace = 0;
2169 ufoClearCondDefines();
2170 ufoWipeIncludeStack();
2172 // release all includes
2173 ufoInFile = NULL;
2174 if (ufoInFileName) free(ufoInFileName);
2175 if (ufoLastIncPath) free(ufoLastIncPath);
2176 if (ufoLastSysIncPath) free(ufoLastSysIncPath);
2177 ufoInFileName = NULL; ufoLastIncPath = NULL; ufoLastSysIncPath = NULL;
2178 ufoInFileNameHash = 0; ufoInFileNameLen = 0;
2179 ufoInFileLine = 0;
2181 free(ufoForthCFAs);
2182 ufoForthCFAs = NULL;
2183 ufoCFAsUsed = 0;
2185 free(ufoImage);
2186 ufoImage = NULL;
2187 ufoImageSize = 0;
2189 ufoMode = UFO_MODE_NATIVE;
2190 ufoForthVocId = 0; ufoCompilerVocId = 0;
2191 ufoSingleStep = 0;
2193 // free all handles
2194 for (uint32_t f = 0; f < ufoHandlesUsed; f += 1) {
2195 UfoHandle *hh = ufoHandles[f];
2196 if (hh != NULL) {
2197 if (hh->data != NULL) free(hh->data);
2198 free(hh);
2201 if (ufoHandles != NULL) free(ufoHandles);
2202 ufoHandles = NULL; ufoHandlesUsed = 0; ufoHandlesAlloted = 0;
2203 ufoHandleFreeList = NULL;
2205 ufoLastEmitWasCR = 1;
2207 ufoClearCondDefines();
2211 //==========================================================================
2213 // ufoDumpWordHeader
2215 //==========================================================================
2216 __attribute__((unused)) static void ufoDumpWordHeader (const uint32_t lfa) {
2217 fprintf(stderr, "=== WORD: LFA: 0x%08x ===\n", lfa);
2218 if (lfa != 0) {
2219 fprintf(stderr, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa)));
2220 fprintf(stderr, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa)));
2221 fprintf(stderr, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa)));
2222 fprintf(stderr, " (LFA): 0x%08x\n", ufoImgGetU32(lfa));
2223 fprintf(stderr, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)));
2224 const uint32_t cfa = UFO_LFA_TO_CFA(lfa);
2225 fprintf(stderr, " CFA: 0x%08x\n", cfa);
2226 fprintf(stderr, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa));
2227 fprintf(stderr, " (CFA): 0x%08x\n", ufoImgGetU32(cfa));
2228 const uint32_t nfa = UFO_LFA_TO_NFA(lfa);
2229 const uint32_t nlen = ufoImgGetU8(nfa);
2230 fprintf(stderr, " NFA: 0x%08x (nlen: %u)\n", nfa, nlen);
2231 const uint32_t flags = ufoImgGetU32(nfa);
2232 fprintf(stderr, " FLAGS: 0x%08x\n", flags);
2233 if ((flags & 0xffff0000U) != 0) {
2234 fprintf(stderr, " FLAGS:");
2235 if (flags & UFW_FLAG_IMMEDIATE) fprintf(stderr, " IMM");
2236 if (flags & UFW_FLAG_SMUDGE) fprintf(stderr, " SMUDGE");
2237 if (flags & UFW_FLAG_NORETURN) fprintf(stderr, " NORET");
2238 if (flags & UFW_FLAG_HIDDEN) fprintf(stderr, " HIDDEN");
2239 if (flags & UFW_FLAG_CBLOCK) fprintf(stderr, " CBLOCK");
2240 if (flags & UFW_FLAG_VOCAB) fprintf(stderr, " VOCAB");
2241 if (flags & UFW_FLAG_SCOLON) fprintf(stderr, " SCOLON");
2242 if (flags & UFW_FLAG_PROTECTED) fprintf(stderr, " PROTECTED");
2243 fputc('\n', stderr);
2245 if ((flags & 0xff00U) != 0) {
2246 fprintf(stderr, " ARGS: ");
2247 switch (flags & UFW_WARG_MASK) {
2248 case UFW_WARG_NONE: fprintf(stderr, "NONE"); break;
2249 case UFW_WARG_BRANCH: fprintf(stderr, "BRANCH"); break;
2250 case UFW_WARG_LIT: fprintf(stderr, "LIT"); break;
2251 case UFW_WARG_C4STRZ: fprintf(stderr, "C4STRZ"); break;
2252 case UFW_WARG_CFA: fprintf(stderr, "CFA"); break;
2253 case UFW_WARG_CBLOCK: fprintf(stderr, "CBLOCK"); break;
2254 case UFW_WARG_VOCID: fprintf(stderr, "VOCID"); break;
2255 case UFW_WARG_C1STRZ: fprintf(stderr, "C1STRZ"); break;
2256 case UFW_WARG_DATASKIP: fprintf(stderr, "DATA"); break;
2257 default: fprintf(stderr, "wtf?!"); break;
2259 fputc('\n', stderr);
2261 fprintf(stderr, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa - 1u), UFO_CFA_TO_NFA(cfa));
2262 fprintf(stderr, " NAME(%u): ", nlen);
2263 for (uint32_t f = 0; f < nlen; f += 1) {
2264 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
2265 if (ch <= 32 || ch >= 127) {
2266 fprintf(stderr, "\\x%02x", ch);
2267 } else {
2268 fprintf(stderr, "%c", (char)ch);
2271 fprintf(stderr, "\n");
2272 ufo_assert(UFO_CFA_TO_LFA(cfa) == lfa);
2277 //==========================================================================
2279 // ufoVocCheckName
2281 // return 0 or CFA
2283 //==========================================================================
2284 static uint32_t ufoVocCheckName (uint32_t lfa, const void *wname, uint32_t wnlen, uint32_t hash,
2285 int allowvochid)
2287 uint32_t res = 0;
2288 #ifdef UFO_DEBUG_FIND_WORD
2289 fprintf(stderr, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
2290 (unsigned) wnlen, (const char *)wname,
2291 lfa, (lfa != 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)) : 0), hash);
2292 ufoDumpWordHeader(lfa);
2293 #endif
2294 if (lfa != 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa)) == hash) {
2295 const uint32_t lenflags = ufoImgGetU32(UFO_LFA_TO_NFA(lfa));
2296 if ((lenflags & UFW_FLAG_SMUDGE) == 0 &&
2297 (allowvochid || (lenflags & UFW_FLAG_HIDDEN) == 0))
2299 const uint32_t nlen = lenflags&0xffU;
2300 if (nlen == wnlen) {
2301 uint32_t naddr = UFO_LFA_TO_NFA(lfa) + 4u;
2302 uint32_t pos = 0;
2303 while (pos < nlen) {
2304 uint8_t c0 = ((const unsigned char *)wname)[pos];
2305 if (c0 >= 'a' && c0 <= 'z') c0 = c0 - 'a' + 'A';
2306 uint8_t c1 = ufoImgGetU8(naddr + pos);
2307 if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A';
2308 if (c0 != c1) break;
2309 pos += 1u;
2311 if (pos == nlen) {
2312 // i found her!
2313 naddr += pos + 1u;
2314 res = UFO_ALIGN4(naddr);
2319 return res;
2323 //==========================================================================
2325 // ufoFindWordInVoc
2327 // return 0 or CFA
2329 //==========================================================================
2330 static uint32_t ufoFindWordInVoc (const void *wname, uint32_t wnlen, uint32_t hash,
2331 uint32_t vocid, int allowvochid)
2333 uint32_t res = 0;
2334 if (wname == NULL) ufo_assert(wnlen == 0);
2335 if (wnlen != 0 && vocid != 0) {
2336 if (hash == 0) hash = joaatHashBufCI(wname, wnlen);
2337 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2338 fprintf(stderr, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
2339 (unsigned) wnlen, (const char *)wname,
2340 vocid, hash, ufoImgGetU32(vocid + UFW_VOCAB_OFS_HTABLE));
2341 #endif
2342 const uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2343 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2344 // hash table present, use it
2345 uint32_t bfa = htbl + (hash % (uint32_t)UFO_HASHTABLE_SIZE) * 4u;
2346 bfa = ufoImgGetU32(bfa);
2347 while (res == 0 && bfa != 0) {
2348 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2349 fprintf(stderr, "IN-VOC: bfa: 0x%08x\n", bfa);
2350 #endif
2351 res = ufoVocCheckName(UFO_BFA_TO_LFA(bfa), wname, wnlen, hash, allowvochid);
2352 bfa = ufoImgGetU32(bfa);
2354 } else {
2355 // no hash table, use linear search
2356 uint32_t lfa = vocid + UFW_VOCAB_OFS_LATEST;
2357 lfa = ufoImgGetU32(lfa);
2358 while (res == 0 && lfa != 0) {
2359 res = ufoVocCheckName(lfa, wname, wnlen, hash, allowvochid);
2360 lfa = ufoImgGetU32(lfa);
2364 return res;
2368 //==========================================================================
2370 // ufoFindColon
2372 // return part after the colon, or `NULL`
2374 //==========================================================================
2375 static const void *ufoFindColon (const void *wname, uint32_t wnlen) {
2376 const void *res = NULL;
2377 if (wnlen != 0) {
2378 ufo_assert(wname != NULL);
2379 const char *str = (const char *)wname;
2380 while (wnlen != 0 && str[0] != ':') {
2381 str += 1; wnlen -= 1;
2383 if (wnlen != 0) {
2384 res = (const void *)(str + 1); // skip colon
2387 return res;
2391 //==========================================================================
2393 // ufoFindWordInVocAndParents
2395 //==========================================================================
2396 static uint32_t ufoFindWordInVocAndParents (const void *wname, uint32_t wnlen, uint32_t hash,
2397 uint32_t vocid, int allowvochid)
2399 uint32_t res = 0;
2400 if (hash == 0) hash = joaatHashBufCI(wname, wnlen);
2401 while (res == 0 && vocid != 0) {
2402 res = ufoFindWordInVoc(wname, wnlen, hash, vocid, allowvochid);
2403 vocid = ufoImgGetU32(vocid + UFW_VOCAB_OFS_PARENT);
2405 return res;
2409 //==========================================================================
2411 // ufoFindWordNameRes
2413 // find with name resolution
2415 // return 0 or CFA
2417 //==========================================================================
2418 static uint32_t ufoFindWordNameRes (const void *wname, uint32_t wnlen) {
2419 uint32_t res = 0;
2420 if (wnlen != 0 && *(const char *)wname != ':') {
2421 ufo_assert(wname != NULL);
2423 const void *stx = wname;
2424 wname = ufoFindColon(wname, wnlen);
2425 if (wname != NULL && wname != stx + wnlen) {
2426 // look in all vocabs (excluding hidden ones)
2427 uint32_t xlen = (uint32_t)(ptrdiff_t)(wname - stx) - 1u;
2428 ufo_assert(xlen > 0 && xlen < 255);
2429 uint32_t xhash = joaatHashBufCI(stx, xlen);
2430 uint32_t voclink = ufoImgGetU32(ufoAddrVocLink);
2431 #ifdef UFO_DEBUG_FIND_WORD_COLON
2432 fprintf(stderr, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2433 (unsigned)xlen, (const char *)stx, xhash, voclink);
2434 #endif
2435 while (res == 0 && voclink != 0) {
2436 const uint32_t vhdraddr = voclink - UFW_VOCAB_OFS_VOCLINK + UFW_VOCAB_OFS_HEADER;
2437 const uint32_t vhdr = ufoImgGetU32(vhdraddr);
2438 if (vhdr != 0) {
2439 res = ufoVocCheckName(UFO_NFA_TO_LFA(vhdr), stx, xlen, xhash, 0);
2441 if (res == 0) voclink = ufoImgGetU32(voclink);
2443 if (res != 0) {
2444 uint32_t vocid = voclink - UFW_VOCAB_OFS_VOCLINK;
2445 ufo_assert(voclink != 0);
2446 wnlen -= xlen + 1;
2447 #ifdef UFO_DEBUG_FIND_WORD_COLON
2448 fprintf(stderr, "searching {%.*s}(%u) in {%.*s}\n",
2449 (unsigned)wnlen, wname, wnlen, (unsigned)xlen, stx);
2450 #endif
2451 while (res != 0 && wname != NULL) {
2452 // first, the whole rest
2453 res = ufoFindWordInVocAndParents(wname, wnlen, 0, vocid, 1);
2454 if (res != 0) {
2455 wname = NULL;
2456 } else {
2457 stx = wname;
2458 wname = ufoFindColon(wname, wnlen);
2459 if (wname == NULL) xlen = wnlen; else xlen = (uint32_t)(ptrdiff_t)(wname - stx) - 1u;
2460 ufo_assert(xlen > 0 && xlen < 255);
2461 res = ufoFindWordInVocAndParents(stx, xlen, 0, vocid, 1);
2462 if (res != 0) {
2463 wnlen -= xlen + 1;
2464 if (wname != NULL) {
2465 // it should be a vocabulary
2466 const uint32_t nfa = UFO_CFA_TO_NFA(res);
2467 if ((ufoImgGetU32(nfa) & UFW_FLAG_VOCAB) != 0) {
2468 vocid = ufoImgGetU32(UFO_CFA_TO_PFA(res)); // pfa points to vocabulary
2469 } else {
2470 res = 0;
2480 return res;
2484 //==========================================================================
2486 // ufoFindWord
2488 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2490 // return 0 or CFA
2492 //==========================================================================
2493 static uint32_t ufoFindWord (const char *wname) {
2494 uint32_t res = 0;
2495 if (wname && wname[0] != 0) {
2496 const size_t wnlen = strlen(wname);
2497 ufo_assert(wnlen < 8192);
2498 uint32_t ctx = ufoImgGetU32(ufoAddrContext);
2499 const uint32_t hash = joaatHashBufCI(wname, (uint32_t)wnlen);
2501 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2503 // first search in context
2504 res = ufoFindWordInVocAndParents(wname, (uint32_t)wnlen, hash, ctx, (ctx == ufoImgGetU32(ufoAddrCurrent)));
2506 // now try vocabulary stack
2507 uint32_t vstp = ufoVSP;
2508 while (res == 0 && vstp != 0) {
2509 vstp -= 1;
2510 ctx = ufoVocStack[vstp];
2511 res = ufoFindWordInVocAndParents(wname, (uint32_t)wnlen, hash, ctx, (ctx == ufoImgGetU32(ufoAddrCurrent)));
2514 // if not found, try name resolution
2515 if (res == 0) res = ufoFindWordNameRes(wname, (uint32_t)wnlen);
2518 return res;
2522 //==========================================================================
2524 // ufoCreateWordHeader
2526 // create word header up to CFA, link to the current dictionary
2528 //==========================================================================
2529 static void ufoCreateWordHeader (const char *wname, uint32_t flags) {
2530 if (wname == NULL) wname = "";
2531 const size_t wnlen = strlen(wname);
2532 ufo_assert(wnlen < UFO_MAX_WORD_LENGTH);
2533 const uint32_t hash = joaatHashBufCI(wname, (uint32_t)wnlen);
2534 const uint32_t curr = ufoImgGetU32(ufoAddrCurrent);
2535 ufo_assert(curr != 0);
2536 // redefine check
2537 const uint32_t warn = ufoImgGetU32(ufoAddrRedefineWarning);
2538 if (wnlen != 0 && warn != UFO_REDEF_WARN_DONT_CARE) {
2539 uint32_t cfa;
2540 if (warn != UFO_REDEF_WARN_PARENTS) {
2541 cfa = ufoFindWordInVoc(wname, wnlen, hash, curr, 1);
2542 } else {
2543 cfa = ufoFindWordInVocAndParents(wname, wnlen, hash, curr, 1);
2545 if (cfa != 0) {
2546 const uint32_t nfa = UFO_CFA_TO_NFA(cfa);
2547 const uint32_t flags = ufoImgGetU32(nfa);
2548 if ((flags & UFW_FLAG_PROTECTED) != 0) {
2549 ufoFatal("trying to redefine protected word '%s'", wname);
2550 } else if (warn != UFO_REDEF_WARN_NONE) {
2551 ufoWarning("redefining word '%s'", wname);
2555 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2556 const uint32_t bkt = (hash % (uint32_t)UFO_HASHTABLE_SIZE) * 4u;
2557 const uint32_t htbl = curr + UFW_VOCAB_OFS_HTABLE;
2558 ufoImgEmitAlign();
2559 const uint32_t xfaAddr = UFO_GET_DP();
2560 if ((xfaAddr & UFO_ADDR_TEMP_BIT) == 0) {
2561 // link previous yfa here
2562 const uint32_t lastxfa = ufoImgGetU32(ufoAddrLastXFA);
2563 // fix YFA of the previous word
2564 if (lastxfa != 0) {
2565 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa), UFO_XFA_TO_YFA(xfaAddr));
2567 // our XFA points to the previous XFA
2568 ufoImgEmitU32(lastxfa); // xfa
2569 // update last XFA
2570 ufoImgPutU32(ufoAddrLastXFA, xfaAddr);
2571 } else {
2572 ufoImgEmitU32(0); // xfa
2574 ufoImgEmitU32(0); // yfa
2575 // bucket link (bfa)
2576 if (wnlen == 0 || ufoImgGetU32(htbl) == UFO_NO_HTABLE_FLAG) {
2577 ufoImgEmitU32(0);
2578 } else {
2579 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2580 fprintf(stderr, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2581 wname, curr, htbl, bkt);
2582 fprintf(stderr, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl + bkt), UFO_GET_DP());
2583 #endif
2584 // bfa points to bfa
2585 const uint32_t bfa = UFO_GET_DP();
2586 ufoImgEmitU32(ufoImgGetU32(htbl + bkt));
2587 ufoImgPutU32(htbl + bkt, bfa);
2589 // lfa
2590 const uint32_t lfa = UFO_GET_DP();
2591 ufoImgEmitU32(ufoImgGetU32(curr + UFW_VOCAB_OFS_LATEST));
2592 // fix voc latest
2593 ufoImgPutU32(curr + UFW_VOCAB_OFS_LATEST, lfa);
2594 // name hash
2595 ufoImgEmitU32(hash);
2596 // name length
2597 const uint32_t nfa = UFO_GET_DP();
2598 ufoImgEmitU32(((uint32_t)wnlen&0xffU) | (flags & 0xffffff00U));
2599 const uint32_t nstart = UFO_GET_DP();
2600 // put name
2601 for (size_t f = 0; f < wnlen; f += 1) {
2602 ufoImgEmitU8(((const unsigned char *)wname)[f]);
2604 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2605 const uint32_t nend = UFO_GET_DP(); // length byte itself is not included
2606 // name length, again
2607 ufo_assert(nend - nstart <= 255);
2608 ufoImgEmitU8((uint8_t)(nend - nstart));
2609 ufo_assert((UFO_GET_DP() & 3) == 0);
2610 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa);
2611 if ((nend & UFO_ADDR_SPECIAL_BITS_MASK) == 0) ufoRecordDebug(nend);
2612 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2613 fprintf(stderr, "*** NEW HEADER ***\n");
2614 fprintf(stderr, "CFA: 0x%08x\n", UFO_GET_DP());
2615 fprintf(stderr, "NSTART: 0x%08x\n", nstart);
2616 fprintf(stderr, "NEND: 0x%08x\n", nend);
2617 fprintf(stderr, "NLEN: %u (%u)\n", nend - nstart, ufoImgGetU8(UFO_GET_DP() - 1u));
2618 ufoDumpWordHeader(lfa);
2619 #endif
2620 #if 0
2621 fprintf(stderr, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname);
2622 #endif
2626 //==========================================================================
2628 // ufoDecompilePart
2630 //==========================================================================
2631 static void ufoDecompilePart (uint32_t addr, uint32_t eaddr, int indent) {
2632 uint32_t count;
2633 FILE *fo = stdout;
2634 while (addr < eaddr) {
2635 uint32_t cfa = ufoImgGetU32(addr);
2636 for (int n = 0; n < indent; n += 1) fputc(' ', fo);
2637 fprintf(fo, "%6u: 0x%08x: ", addr, cfa);
2638 uint32_t nfa = UFO_CFA_TO_NFA(cfa);
2639 uint32_t flags = ufoImgGetU32(nfa);
2640 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2641 uint32_t nlen = flags & 0xffU;
2642 for (uint32_t f = 0; f < nlen; f += 1) {
2643 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
2644 if (ch <= 32 || ch >= 127) {
2645 fprintf(fo, "\\x%02x", ch);
2646 } else {
2647 fprintf(fo, "%c", (char)ch);
2650 addr += 4u;
2651 switch (flags & UFW_WARG_MASK) {
2652 case UFW_WARG_NONE:
2653 break;
2654 case UFW_WARG_BRANCH:
2655 fprintf(fo, " @%u", ufoImgGetU32(addr)); addr += 4u;
2656 break;
2657 case UFW_WARG_LIT:
2658 fprintf(fo, " %u : %d : 0x%08x", ufoImgGetU32(addr),
2659 (int32_t)ufoImgGetU32(addr), ufoImgGetU32(addr)); addr += 4u;
2660 break;
2661 case UFW_WARG_C4STRZ:
2662 count = ufoImgGetU32(addr); addr += 4;
2663 print_str:
2664 fprintf(fo, " str:");
2665 for (int f = 0; f < count; f += 1) {
2666 const uint8_t ch = ufoImgGetU8(addr); addr += 1u;
2667 if (ch <= 32 || ch >= 127) {
2668 fprintf(fo, "\\x%02x", ch);
2669 } else {
2670 fprintf(fo, "%c", (char)ch);
2673 addr += 1u; // skip zero byte
2674 addr = UFO_ALIGN4(addr);
2675 break;
2676 case UFW_WARG_CFA:
2677 cfa = ufoImgGetU32(addr); addr += 4u;
2678 fprintf(fo, " CFA:%u: ", cfa);
2679 nfa = UFO_CFA_TO_NFA(cfa);
2680 nlen = ufoImgGetU8(nfa);
2681 for (uint32_t f = 0; f < nlen; f += 1) {
2682 const uint8_t ch = ufoImgGetU8(nfa + 4u + f);
2683 if (ch <= 32 || ch >= 127) {
2684 fprintf(fo, "\\x%02x", ch);
2685 } else {
2686 fprintf(fo, "%c", (char)ch);
2689 break;
2690 case UFW_WARG_CBLOCK:
2691 fprintf(fo, " CBLOCK:%u", ufoImgGetU32(addr)); addr += 4u;
2692 break;
2693 case UFW_WARG_VOCID:
2694 fprintf(fo, " VOCID:%u", ufoImgGetU32(addr)); addr += 4u;
2695 break;
2696 case UFW_WARG_C1STRZ:
2697 count = ufoImgGetU8(addr); addr += 1;
2698 goto print_str;
2699 case UFW_WARG_DATASKIP:
2700 fprintf(fo, " DATA:%u", ufoImgGetU32(addr));
2701 addr += ufoImgGetU32(addr) + 4u;
2702 break;
2703 default:
2704 fprintf(fo, " -- WTF?!\n");
2705 abort();
2707 fputc('\n', fo);
2712 //==========================================================================
2714 // ufoDecompileWord
2716 //==========================================================================
2717 static void ufoDecompileWord (const uint32_t cfa) {
2718 if (cfa != 0) {
2719 const uint32_t lfa = UFO_CFA_TO_LFA(cfa);
2720 fprintf(stdout, "#### DECOMPILING CFA %u ###\n", cfa);
2721 ufoDumpWordHeader(lfa);
2722 const uint32_t yfa = ufoGetWordEndAddr(cfa);
2723 if (ufoImgGetU32(cfa) == ufoDoForthCFA) {
2724 fprintf(stdout, "--- DECOMPILED CODE ---\n");
2725 ufoDecompilePart(UFO_CFA_TO_PFA(cfa), yfa, 0);
2726 fprintf(stdout, "=======================\n");
2732 //==========================================================================
2734 // ufoBTShowWordName
2736 //==========================================================================
2737 static void ufoBTShowWordName (uint32_t nfa) {
2738 if (nfa != 0) {
2739 uint32_t len = ufoImgGetU8(nfa); nfa += 4u;
2740 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2741 while (len != 0) {
2742 uint8_t ch = ufoImgGetU8(nfa); nfa += 1u; len -= 1u;
2743 if (ch <= 32 || ch >= 127) {
2744 fprintf(stderr, "\\x%02x", ch);
2745 } else {
2746 fprintf(stderr, "%c", (char)ch);
2753 //==========================================================================
2755 // ufoBacktrace
2757 //==========================================================================
2758 static void ufoBacktrace (uint32_t ip, int showDataStack) {
2759 // dump data stack (top 16)
2760 ufoFlushOutput();
2761 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2763 if (showDataStack) {
2764 fprintf(stderr, "***UFO STACK DEPTH: %u\n", ufoSP);
2765 uint32_t xsp = ufoSP;
2766 if (xsp > 16) xsp = 16;
2767 for (uint32_t sp = 0; sp < xsp; ++sp) {
2768 fprintf(stderr, " %2u: 0x%08x %d%s\n",
2769 sp, ufoDStack[xsp - sp - 1], (int32_t)ufoDStack[xsp - sp - 1],
2770 (sp == 0 ? " -- TOS" : ""));
2772 if (ufoSP > 16) fprintf(stderr, " ...more...\n");
2775 // dump return stack (top 32)
2776 uint32_t nfa;
2777 uint32_t fline;
2778 const char *fname;
2780 fprintf(stderr, "***UFO RETURN STACK DEPTH: %u\n", ufoRP);
2781 if (ip != 0) {
2782 nfa = ufoFindWordForIP(ip);
2783 if (nfa != 0) {
2784 fprintf(stderr, " **: %8u -- ", ip);
2785 ufoBTShowWordName(nfa);
2786 fname = ufoFindFileForIP(ip, &fline, NULL, NULL);
2787 if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }
2788 fputc('\n', stderr);
2791 uint32_t rp = ufoRP;
2792 uint32_t rscount = 0;
2793 if (rp > UFO_RSTACK_SIZE) rp = UFO_RSTACK_SIZE;
2794 while (rscount != 32 && rp != 0) {
2795 rp -= 1;
2796 const uint32_t val = ufoRStack[rp];
2797 nfa = ufoFindWordForIP(val - 4u);
2798 if (nfa != 0) {
2799 fprintf(stderr, " %2u: %8u -- ", ufoRP - rp - 1u, val);
2800 ufoBTShowWordName(nfa);
2801 fname = ufoFindFileForIP(val - 4u, &fline, NULL, NULL);
2802 if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }
2803 fputc('\n', stderr);
2804 } else {
2805 fprintf(stderr, " %2u: 0x%08x %d\n", ufoRP - rp - 1u, val, (int32_t)val);
2807 rscount += 1;
2809 if (ufoRP > 32) fprintf(stderr, " ...more...\n");
2811 ufoFlushOutput();
2815 //==========================================================================
2817 // ufoDumpVocab
2819 //==========================================================================
2821 static void ufoDumpVocab (uint32_t vocid) {
2822 if (vocid != 0) {
2823 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2824 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2825 vochdr = ufoImgGetU32(vochdr);
2826 if (vochdr != 0) {
2827 fprintf(stderr, "--- HEADER ---\n");
2828 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2829 fprintf(stderr, "========\n");
2830 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2831 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2832 fprintf(stderr, "--- HASH TABLE ---\n");
2833 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2834 uint32_t bfa = ufoImgGetU32(htbl);
2835 if (bfa != 0) {
2836 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2837 do {
2838 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2839 bfa = ufoImgGetU32(bfa);
2840 } while (bfa != 0);
2842 htbl += 4u;
2851 // if set, this will be used when we are out of include files. intended for UrAsm.
2852 // return 0 if there is no more lines, otherwise the string should be copied
2853 // to buffer, `*fname` and `*fline` should be properly set.
2854 int (*ufoFileReadLine) (void *buf, size_t bufsize, const char **fname, int *fline) = NULL;
2857 //==========================================================================
2859 // ufoLoadNextUserLine
2861 //==========================================================================
2862 static int ufoLoadNextUserLine (void) {
2863 uint32_t tibPos = 0;
2864 const char *fname = NULL;
2865 int fline = 0;
2866 ufoResetTib();
2867 if (ufoFileReadLine != NULL && ufoFileReadLine(ufoCurrFileLine, 510, &fname, &fline) != 0) {
2868 ufoCurrFileLine[510] = 0;
2869 uint32_t slen = (uint32_t)strlen(ufoCurrFileLine);
2870 while (slen != 0 && (ufoCurrFileLine[slen - 1u] == 10 || ufoCurrFileLine[slen - 1u] == 13)) {
2871 slen -= 1u;
2873 if (tibPos + slen + 1u > UFO_ADDR_HANDLE_OFS_MASK) {
2874 ufoFatal("input text line too long (at least %u bytes)", tibPos + slen);
2876 ufoTibEnsureSize(tibPos + slen + 1u);
2877 for (uint32_t f = 0; f < slen; f += 1) {
2878 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine)[f], tibPos + f);
2880 ufoTibPokeChOfs(0, tibPos + slen);
2881 tibPos += slen;
2882 if (fname == NULL) fname = "<user>";
2883 ufoSetInFileName(fname);
2884 ufoInFileLine = fline;
2885 return 1;
2886 } else {
2887 return 0;
2892 //==========================================================================
2894 // ufoLoadNextLine_NativeMode
2896 // load next file line into TIB
2897 // always strips final '\n'
2899 // return 0 on EOF, 1 on success
2901 //==========================================================================
2902 static int ufoLoadNextLine (int crossInclude) {
2903 int done = 0;
2904 uint32_t tibPos = 0;
2905 ufoResetTib();
2907 if (ufoMode == UFO_MODE_MACRO) {
2908 //fprintf(stderr, "***MAC!\n");
2909 return 0;
2912 while (ufoInFile != NULL && !done) {
2913 ufoCurrIncludeLineFileOfs = ftell(ufoInFile);
2914 if (fgets(ufoCurrFileLine, 510, ufoInFile) != NULL) {
2915 // check for a newline
2916 // if there is no newline char at the end, the string was truncated
2917 ufoCurrFileLine[510] = 0;
2918 const uint32_t slen = (uint32_t)strlen(ufoCurrFileLine);
2919 if (tibPos + slen + 1u > UFO_ADDR_HANDLE_OFS_MASK) {
2920 ufoFatal("input text line too long (at least %u bytes)", tibPos + slen);
2922 ufoTibEnsureSize(tibPos + slen + 1u);
2923 for (uint32_t f = 0; f < slen; f += 1) {
2924 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine)[f], tibPos + f);
2926 ufoTibPokeChOfs(0, tibPos + slen);
2927 tibPos += slen;
2928 if (slen != 0 && (ufoCurrFileLine[slen - 1u] == 13 || ufoCurrFileLine[slen - 1u] == 10)) {
2929 ++ufoInFileLine;
2930 done = 1;
2931 } else {
2932 // continuation, nothing to do
2934 } else {
2935 // if we read nothing, this is EOF
2936 if (tibPos == 0 && crossInclude) {
2937 // we read nothing, and allowed to cross include boundaries
2938 ufoPopInFile();
2939 } else {
2940 done = 1;
2945 if (tibPos == 0) {
2946 // eof, try user-supplied input
2947 if (ufoFileStackPos == 0) {
2948 return ufoLoadNextUserLine();
2949 } else {
2950 return 0;
2952 } else {
2953 // if we read at least something, this is not EOF
2954 return 1;
2959 // ////////////////////////////////////////////////////////////////////////// //
2960 // debug
2962 // DUMP-STACK
2963 // ( -- )
2964 UFWORD(DUMP_STACK) {
2965 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2966 printf("***UFO STACK DEPTH: %u\n", ufoSP);
2967 uint32_t xsp = ufoSP;
2968 if (xsp > 16) xsp = 16;
2969 for (uint32_t sp = 0; sp < xsp; ++sp) {
2970 printf(" %2u: 0x%08x %d%s\n",
2971 sp, ufoDStack[xsp - sp - 1], (int32_t)ufoDStack[xsp - sp - 1],
2972 (sp == 0 ? " -- TOS" : ""));
2974 if (ufoSP > 16) printf(" ...more...\n");
2975 ufoLastEmitWasCR = 1;
2978 // BACKTRACE
2979 // ( -- )
2980 UFWORD(UFO_BACKTRACE) {
2981 ufoFlushOutput();
2982 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
2983 if (ufoInFile != NULL) {
2984 fprintf(stderr, "*** at file %s, line %d ***\n", ufoInFileName, ufoInFileLine);
2985 } else {
2986 fprintf(stderr, "*** somewhere in time ***\n");
2988 ufoBacktrace(ufoIP, 1);
2991 // DUMP-STACK-TASK
2992 // ( stid -- )
2993 UFWORD(DUMP_STACK_TASK) {
2994 UfoState *st = ufoFindState(ufoPop());
2995 if (st == NULL) ufoFatal("invalid state id");
2996 // temporarily switch the task
2997 UfoState *oldst = ufoCurrState; ufoCurrState = st;
2998 // dump
2999 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
3000 printf("***UFO STACK DEPTH: %u\n", ufoSP);
3001 uint32_t xsp = ufoSP;
3002 if (xsp > 16) xsp = 16;
3003 for (uint32_t sp = 0; sp < xsp; ++sp) {
3004 printf(" %2u: 0x%08x %d%s\n",
3005 sp, ufoDStack[xsp - sp - 1], (int32_t)ufoDStack[xsp - sp - 1],
3006 (sp == 0 ? " -- TOS" : ""));
3008 if (ufoSP > 16) printf(" ...more...\n");
3009 ufoLastEmitWasCR = 1;
3010 // restore state
3011 ufoCurrState = oldst;
3014 // DUMP-RSTACK-TASK
3015 // ( stid -- )
3016 UFWORD(DUMP_RSTACK_TASK) {
3017 UfoState *st = ufoFindState(ufoPop());
3018 if (st == NULL) ufoFatal("invalid state id");
3019 // temporarily switch the task
3020 UfoState *oldst = ufoCurrState; ufoCurrState = st;
3021 // dump
3022 ufoFlushOutput();
3023 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
3024 if (ufoInFile != NULL) {
3025 fprintf(stderr, "*** at file %s, line %d ***\n", ufoInFileName, ufoInFileLine);
3026 } else {
3027 fprintf(stderr, "*** somewhere in time ***\n");
3029 ufoBacktrace(ufoIP, 0);
3030 // restore state
3031 ufoCurrState = oldst;
3034 // BACKTRACE-TASK
3035 // ( stid -- )
3036 UFWORD(UFO_BACKTRACE_TASK) {
3037 UfoState *st = ufoFindState(ufoPop());
3038 if (st == NULL) ufoFatal("invalid state id");
3039 // temporarily switch the task
3040 UfoState *oldst = ufoCurrState; ufoCurrState = st;
3041 // dump
3042 ufoFlushOutput();
3043 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
3044 if (ufoInFile != NULL) {
3045 fprintf(stderr, "*** at file %s, line %d ***\n", ufoInFileName, ufoInFileLine);
3046 } else {
3047 fprintf(stderr, "*** somewhere in time ***\n");
3049 ufoBacktrace(ufoIP, 1);
3050 // restore state
3051 ufoCurrState = oldst;
3055 // ////////////////////////////////////////////////////////////////////////// //
3056 // some init words, and PAD
3059 // SP0!
3060 // ( -- )
3061 UFWORD(SP0_STORE) { ufoSP = 0; }
3063 // RP0!
3064 // ( -- )
3065 UFWORD(RP0_STORE) {
3066 if (ufoRP != ufoRPTop) {
3067 ufoRP = ufoRPTop;
3068 // we need to push a dummy value
3069 ufoRPush(0xdeadf00d);
3073 // PAD
3074 // ( -- pad )
3075 // PAD is at the beginning of temp area
3076 UFWORD(PAD) {
3077 ufoPush(UFO_PAD_ADDR);
3081 // ////////////////////////////////////////////////////////////////////////// //
3082 // peeks and pokes with address register
3085 // A>
3086 // ( -- regA )
3087 UFWORD(REGA_LOAD) {
3088 ufoPush(ufoRegA);
3091 // >A
3092 // ( regA -- )
3093 UFWORD(REGA_STORE) {
3094 ufoRegA = ufoPop();
3097 // A-SWAP
3098 // ( regA -- oldA )
3099 // swap TOS and A
3100 UFWORD(REGA_SWAP) {
3101 const uint32_t newa = ufoPop();
3102 ufoPush(ufoRegA);
3103 ufoRegA = newa;
3106 // +1>A
3107 // ( -- )
3108 UFWORD(REGA_INC) {
3109 ufoRegA += 1u;
3112 // +4>A
3113 // ( -- )
3114 UFWORD(REGA_INC_CELL) {
3115 ufoRegA += 4u;
3118 // A>R
3119 // ( -- | rega )
3120 UFWORD(REGA_TO_R) {
3121 ufoRPush(ufoRegA);
3124 // R>A
3125 // ( | rega -- )
3126 UFWORD(R_TO_REGA) {
3127 ufoRegA = ufoRPop();
3131 // ////////////////////////////////////////////////////////////////////////// //
3132 // useful to work with handles and normal addreses uniformly
3135 // C@A+
3136 // ( idx -- byte )
3137 UFWORD(CPEEK_REGA_IDX) {
3138 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3139 const uint32_t idx = ufoPop();
3140 const uint32_t newaddr = ufoRegA + idx;
3141 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK)) {
3142 ufoPush(ufoImgGetU8Ext(newaddr));
3143 } else {
3144 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3145 ufoRegA, idx, newaddr);
3147 } else {
3148 ufoPush(ufoRegA);
3149 UFCALL(PAR_HANDLE_LOAD_BYTE);
3153 // W@A+
3154 // ( idx -- word )
3155 UFWORD(WPEEK_REGA_IDX) {
3156 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3157 const uint32_t idx = ufoPop();
3158 const uint32_t newaddr = ufoRegA + idx;
3159 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
3160 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 1u) & UFO_ADDR_SPECIAL_BITS_MASK))
3162 ufoPush(ufoImgGetU16(newaddr));
3163 } else {
3164 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3165 ufoRegA, idx, newaddr);
3167 } else {
3168 ufoPush(ufoRegA);
3169 UFCALL(PAR_HANDLE_LOAD_WORD);
3173 // @A+
3174 // ( idx -- value )
3175 UFWORD(PEEK_REGA_IDX) {
3176 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3177 const uint32_t idx = ufoPop();
3178 const uint32_t newaddr = ufoRegA + idx;
3179 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
3180 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 3u) & UFO_ADDR_SPECIAL_BITS_MASK))
3182 ufoPush(ufoImgGetU32(newaddr));
3183 } else {
3184 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3185 ufoRegA, idx, newaddr);
3187 } else {
3188 ufoPush(ufoRegA);
3189 UFCALL(PAR_HANDLE_LOAD_CELL);
3193 // C!A+
3194 // ( byte idx -- )
3195 UFWORD(CPOKE_REGA_IDX) {
3196 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3197 const uint32_t idx = ufoPop();
3198 const uint32_t newaddr = ufoRegA + idx;
3199 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK)) {
3200 const uint32_t value = ufoPop();
3201 ufoImgPutU8(newaddr, value);
3202 } else {
3203 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3204 ufoRegA, idx, newaddr);
3206 } else {
3207 ufoPush(ufoRegA);
3208 UFCALL(PAR_HANDLE_STORE_BYTE);
3212 // W!A+
3213 // ( word idx -- )
3214 UFWORD(WPOKE_REGA_IDX) {
3215 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3216 const uint32_t idx = ufoPop();
3217 const uint32_t newaddr = ufoRegA + idx;
3218 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
3219 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 1u) & UFO_ADDR_SPECIAL_BITS_MASK))
3221 const uint32_t value = ufoPop();
3222 ufoImgPutU16(newaddr, value);
3223 } else {
3224 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3225 ufoRegA, idx, newaddr);
3227 } else {
3228 ufoPush(ufoRegA);
3229 UFCALL(PAR_HANDLE_STORE_WORD);
3233 // !A+
3234 // ( value idx -- )
3235 UFWORD(POKE_REGA_IDX) {
3236 if ((ufoRegA & UFO_ADDR_HANDLE_BIT) == 0) {
3237 const uint32_t idx = ufoPop();
3238 const uint32_t newaddr = ufoRegA + idx;
3239 if ((ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == (newaddr & UFO_ADDR_SPECIAL_BITS_MASK) &&
3240 (ufoRegA & UFO_ADDR_SPECIAL_BITS_MASK) == ((newaddr + 3u) & UFO_ADDR_SPECIAL_BITS_MASK))
3242 const uint32_t value = ufoPop();
3243 ufoImgPutU32(newaddr, value);
3244 } else {
3245 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3246 ufoRegA, idx, newaddr);
3248 } else {
3249 ufoPush(ufoRegA);
3250 UFCALL(PAR_HANDLE_STORE_CELL);
3255 // ////////////////////////////////////////////////////////////////////////// //
3256 // peeks and pokes
3259 // C@
3260 // ( addr -- value8 )
3261 UFWORD(CPEEK) {
3262 ufoPush(ufoImgGetU8Ext(ufoPop()));
3265 // W@
3266 // ( addr -- value16 )
3267 UFWORD(WPEEK) {
3268 const uint32_t addr = ufoPop();
3269 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
3270 ufoPush(ufoImgGetU16(addr));
3271 } else {
3272 ufoPush(0);
3273 ufoPush(addr);
3274 UFCALL(PAR_HANDLE_LOAD_WORD);
3278 // @
3279 // ( addr -- value32 )
3280 UFWORD(PEEK) {
3281 const uint32_t addr = ufoPop();
3282 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
3283 ufoPush(ufoImgGetU32(addr));
3284 } else {
3285 ufoPush(0);
3286 ufoPush(addr);
3287 UFCALL(PAR_HANDLE_LOAD_CELL);
3291 // C!
3292 // ( val8 addr -- )
3293 UFWORD(CPOKE) {
3294 const uint32_t addr = ufoPop();
3295 const uint32_t val = ufoPop();
3296 ufoImgPutU8Ext(addr, val);
3299 // W!
3300 // ( val16 addr -- )
3301 UFWORD(WPOKE) {
3302 const uint32_t addr = ufoPop();
3303 const uint32_t val = ufoPop();
3304 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
3305 ufoImgPutU16(addr, val);
3306 } else {
3307 ufoPush(val);
3308 ufoPush(0);
3309 ufoPush(addr);
3310 UFCALL(PAR_HANDLE_STORE_WORD);
3314 // !
3315 // ( val32 addr -- )
3316 UFWORD(POKE) {
3317 const uint32_t addr = ufoPop();
3318 const uint32_t val = ufoPop();
3319 if ((addr & UFO_ADDR_HANDLE_BIT) == 0) {
3320 ufoImgPutU32(addr, val);
3321 } else {
3322 ufoPush(val);
3323 ufoPush(0);
3324 ufoPush(addr);
3325 UFCALL(PAR_HANDLE_STORE_CELL);
3330 // ////////////////////////////////////////////////////////////////////////// //
3331 // dictionary emitters
3334 // C,
3335 // ( val8 -- )
3336 UFWORD(CCOMMA) { const uint32_t val = ufoPop(); ufoImgEmitU8(val); }
3338 // W,
3339 // ( val16 -- )
3340 UFWORD(WCOMMA) { const uint32_t val = ufoPop(); ufoImgEmitU8(val&0xffU); ufoImgEmitU8((val >> 8)&0xffU); }
3342 // ,
3343 // ( val -- )
3344 UFWORD(COMMA) { const uint32_t val = ufoPop(); ufoImgEmitU32(val); }
3347 // ////////////////////////////////////////////////////////////////////////// //
3348 // literal pushers
3351 // (LIT) ( -- n )
3352 UFWORD(PAR_LIT) {
3353 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
3354 ufoPush(v);
3357 // (LITCFA) ( -- n )
3358 UFWORD(PAR_LITCFA) {
3359 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
3360 ufoPush(v);
3363 // (LITVOCID) ( -- n )
3364 UFWORD(PAR_LITVOCID) {
3365 const uint32_t v = ufoImgGetU32(ufoIP); ufoIP += 4;
3366 ufoPush(v);
3369 // (LITSTR8)
3370 UFWORD(PAR_LITSTR8) {
3371 const uint32_t count = ufoImgGetU8(ufoIP); ufoIP += 1;
3372 ufoPush(ufoIP);
3373 ufoPush(count);
3374 ufoIP += count + 1; // 1 for terminating 0
3375 // align
3376 ufoIP = UFO_ALIGN4(ufoIP);
3380 // ////////////////////////////////////////////////////////////////////////// //
3381 // jumps, etc.
3384 // (BRANCH) ( -- )
3385 UFWORD(PAR_BRANCH) {
3386 ufoIP = ufoImgGetU32(ufoIP);
3389 // (TBRANCH) ( flag )
3390 UFWORD(PAR_TBRANCH) {
3391 if (ufoPop()) {
3392 ufoIP = ufoImgGetU32(ufoIP);
3393 } else {
3394 ufoIP += 4;
3398 // (0BRANCH) ( flag )
3399 UFWORD(PAR_0BRANCH) {
3400 if (!ufoPop()) {
3401 ufoIP = ufoImgGetU32(ufoIP);
3402 } else {
3403 ufoIP += 4;
3407 // (+0BRANCH) ( flag )
3408 UFWORD(PAR_P0BRANCH) {
3409 if ((ufoPop() & 0x80000000u) == 0) {
3410 ufoIP = ufoImgGetU32(ufoIP);
3411 } else {
3412 ufoIP += 4;
3416 // (+BRANCH) ( flag )
3417 UFWORD(PAR_PBRANCH) {
3418 const uint32_t v = ufoPop();
3419 if (v > 0 && v < 0x80000000u) {
3420 ufoIP = ufoImgGetU32(ufoIP);
3421 } else {
3422 ufoIP += 4;
3426 // (-0BRANCH) ( flag )
3427 UFWORD(PAR_M0BRANCH) {
3428 const uint32_t v = ufoPop();
3429 if (v == 0 || v >= 0x80000000u) {
3430 ufoIP = ufoImgGetU32(ufoIP);
3431 } else {
3432 ufoIP += 4;
3436 // (-BRANCH) ( flag )
3437 UFWORD(PAR_MBRANCH) {
3438 if ((ufoPop() & 0x80000000u) != 0) {
3439 ufoIP = ufoImgGetU32(ufoIP);
3440 } else {
3441 ufoIP += 4;
3445 // (DATASKIP) ( -- )
3446 UFWORD(PAR_DATASKIP) {
3447 ufoIP += ufoImgGetU32(ufoIP) + 4u;
3450 // (OR-BRANCH)
3451 // ( !0 -- !0 ) -- jmp
3452 // ( 0 -- ) -- no jmp
3453 UFWORD(PAR_OR_BRANCH) {
3454 if (ufoPeek() != 0) {
3455 ufoIP = ufoImgGetU32(ufoIP);
3456 } else {
3457 ufoDrop();
3458 ufoIP += 4;
3462 // (AND-BRANCH)
3463 // ( 0 -- 0 ) -- jmp
3464 // ( !0 -- ) -- no jmp
3465 UFWORD(PAR_AND_BRANCH) {
3466 if (ufoPeek() == 0) {
3467 ufoIP = ufoImgGetU32(ufoIP);
3468 } else {
3469 ufoDrop();
3470 ufoIP += 4;
3474 // (CASE-BRANCH)
3475 // ( 0 -- ) -- jmp
3476 // ( n !0 -- ) -- no jmp
3477 UFWORD(PAR_CASE_BRANCH) {
3478 if (ufoPop() == 0) {
3479 ufoIP = ufoImgGetU32(ufoIP);
3480 } else {
3481 ufoDrop();
3482 ufoIP += 4;
3487 // ////////////////////////////////////////////////////////////////////////// //
3488 // execute words by CFA
3491 // EXECUTE ( cfa )
3492 UFWORD(EXECUTE) {
3493 ufoRPush(ufoPop());
3494 ufoVMRPopCFA = 1;
3497 // EXECUTE-TAIL ( cfa )
3498 UFWORD(EXECUTE_TAIL) {
3499 ufoIP = ufoRPop();
3500 ufoRPush(ufoPop());
3501 ufoVMRPopCFA = 1;
3504 // (FORTH-CALL) ( pfa )
3505 UFWORD(FORTH_CALL) {
3506 ufoRPush(ufoIP);
3507 ufoIP = ufoPop();
3511 // ////////////////////////////////////////////////////////////////////////// //
3512 // word termination, locals support
3515 // (EXIT)
3516 UFWORD(PAR_EXIT) {
3517 ufoIP = ufoRPop();
3520 // (L-ENTER)
3521 // ( loccount -- )
3522 UFWORD(PAR_LENTER) {
3523 // low byte of loccount is total number of locals
3524 // high byte is the number of args
3525 uint32_t lcount = ufoImgGetU32(ufoIP); ufoIP += 4u;
3526 uint32_t acount = (lcount >> 8) & 0xff;
3527 lcount &= 0xff;
3528 if (lcount == 0 || lcount < acount) ufoFatal("invalid call to (L-ENTER)");
3529 if ((ufoLBP != 0 && ufoLBP >= ufoLP) || UFO_LSTACK_SIZE - ufoLP <= lcount + 2) {
3530 ufoFatal("out of locals stack");
3532 uint32_t newbp;
3533 if (ufoLP == 0) { ufoLP = 1; newbp = 1; } else newbp = ufoLP;
3534 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3535 ufoLStack[ufoLP] = ufoLBP; ufoLP += 1;
3536 ufoLBP = newbp; ufoLP += lcount;
3537 // and copy args
3538 newbp += acount;
3539 while (newbp != ufoLBP) {
3540 ufoLStack[newbp] = ufoPop();
3541 newbp -= 1;
3545 // (L-LEAVE)
3546 UFWORD(PAR_LLEAVE) {
3547 if (ufoLBP == 0) ufoFatal("(L-LEAVE) with empty locals stack");
3548 if (ufoLBP >= ufoLP) ufoFatal("(L-LEAVE) broken locals stack");
3549 ufoLP = ufoLBP;
3550 ufoLBP = ufoLStack[ufoLBP];
3553 //==========================================================================
3555 // ufoLoadLocal
3557 //==========================================================================
3558 UFO_FORCE_INLINE void ufoLoadLocal (const uint32_t lidx) {
3559 if (lidx == 0 || lidx >= UFO_LSTACK_SIZE) ufoFatal("invalid local index");
3560 if (ufoLBP == 0 || ufoLBP >= ufoLP || ufoLP - ufoLBP <= lidx) ufoFatal("invalid local index");
3561 ufoPush(ufoLStack[ufoLBP + lidx]);
3564 //==========================================================================
3566 // ufoStoreLocal
3568 //==========================================================================
3569 UFO_FORCE_INLINE void ufoStoreLocal (const uint32_t lidx) {
3570 const uint32_t value = ufoPop();
3571 if (lidx == 0 || lidx >= UFO_LSTACK_SIZE) ufoFatal("invalid local index");
3572 if (ufoLBP == 0 || ufoLBP >= ufoLP || ufoLP - ufoLBP <= lidx) ufoFatal("invalid local index");
3573 ufoLStack[ufoLBP + lidx] = value;
3576 // (LOCAL@)
3577 // ( idx -- value )
3578 UFWORD(PAR_LOCAL_LOAD) { ufoLoadLocal(ufoPop()); }
3580 // (LOCAL!)
3581 // ( value idx -- )
3582 UFWORD(PAR_LOCAL_STORE) { ufoStoreLocal(ufoPop()); }
3585 // ////////////////////////////////////////////////////////////////////////// //
3586 // stack manipulation
3589 // DUP
3590 // ( n -- n n )
3591 UFWORD(DUP) { ufoDup(); }
3592 // ?DUP
3593 // ( n -- n n ) | ( 0 -- 0 )
3594 UFWORD(QDUP) { if (ufoPeek()) ufoDup(); }
3595 // 2DUP
3596 // ( n0 n1 -- n0 n1 n0 n1 )
3597 UFWORD(DDUP) { ufo2Dup(); }
3598 // DROP
3599 // ( n -- )
3600 UFWORD(DROP) { ufoDrop(); }
3601 // 2DROP
3602 // ( n0 n1 -- )
3603 UFWORD(DDROP) { ufo2Drop(); }
3604 // SWAP
3605 // ( n0 n1 -- n1 n0 )
3606 UFWORD(SWAP) { ufoSwap(); }
3607 // 2SWAP
3608 // ( n0 n1 -- n1 n0 )
3609 UFWORD(DSWAP) { ufo2Swap(); }
3610 // OVER
3611 // ( n0 n1 -- n0 n1 n0 )
3612 UFWORD(OVER) { ufoOver(); }
3613 // 2OVER
3614 // ( n0 n1 -- n0 n1 n0 )
3615 UFWORD(DOVER) { ufo2Over(); }
3616 // ROT
3617 // ( n0 n1 n2 -- n1 n2 n0 )
3618 UFWORD(ROT) { ufoRot(); }
3619 // NROT
3620 // ( n0 n1 n2 -- n2 n0 n1 )
3621 UFWORD(NROT) { ufoNRot(); }
3623 // RDUP
3624 // ( n -- n n )
3625 UFWORD(RDUP) { ufoRDup(); }
3626 // RDROP
3627 // ( n -- )
3628 UFWORD(RDROP) { ufoRDrop(); }
3630 // >R
3631 // ( n -- | n )
3632 UFWORD(DTOR) { ufoRPush(ufoPop()); }
3633 // R>
3634 // ( | n -- n )
3635 UFWORD(RTOD) { ufoPush(ufoRPop()); }
3636 // R@
3637 // ( | n -- n | n)
3638 UFWORD(RPEEK) { ufoPush(ufoRPeek()); }
3640 // PICK
3641 // ( idx -- n )
3642 UFWORD(PICK) {
3643 const uint32_t n = ufoPop();
3644 if (n >= ufoSP) ufoFatal("invalid PICK index %u", n);
3645 ufoPush(ufoDStack[ufoSP - n - 1u]);
3648 // RPICK
3649 // ( idx -- n )
3650 UFWORD(RPICK) {
3651 const uint32_t n = ufoPop();
3652 if (n >= ufoRP - ufoRPTop) ufoFatal("invalid RPICK index %u", n);
3653 const uint32_t rp = ufoRP - n - 1u;
3654 ufoPush(ufoRStack[rp]);
3657 // ROLL
3658 // ( idx -- n )
3659 UFWORD(ROLL) {
3660 const uint32_t n = ufoPop();
3661 if (n >= ufoSP) ufoFatal("invalid ROLL index %u", n);
3662 switch (n) {
3663 case 0: break; // do nothing
3664 case 1: ufoSwap(); break;
3665 case 2: ufoRot(); break;
3666 default:
3668 const uint32_t val = ufoDStack[ufoSP - n - 1u];
3669 for (uint32_t f = ufoSP - n; f < ufoSP; f += 1) ufoDStack[f - 1] = ufoDStack[f];
3670 ufoDStack[ufoSP - 1u] = val;
3672 break;
3676 // RROLL
3677 // ( idx -- n )
3678 UFWORD(RROLL) {
3679 const uint32_t n = ufoPop();
3680 if (n >= ufoRP - ufoRPTop) ufoFatal("invalid RROLL index %u", n);
3681 if (n != 0) {
3682 const uint32_t rp = ufoRP - n - 1u;
3683 const uint32_t val = ufoRStack[rp];
3684 for (uint32_t f = rp + 1u; f < ufoRP; f += 1u) ufoRStack[f - 1u] = ufoRStack[f];
3685 ufoRStack[ufoRP - 1u] = val;
3689 // RSWAP
3690 // ( | a b -- | b a )
3691 UFWORD(RSWAP) {
3692 const uint32_t b = ufoRPop();
3693 const uint32_t a = ufoRPop();
3694 ufoRPush(b); ufoRPush(a);
3697 // ROVER
3698 // ( | a b -- | a b a )
3699 UFWORD(ROVER) {
3700 const uint32_t b = ufoRPop();
3701 const uint32_t a = ufoRPop();
3702 ufoRPush(a); ufoRPush(b); ufoRPush(a);
3705 // RROT
3706 // ( | a b c -- | b c a )
3707 UFWORD(RROT) {
3708 const uint32_t c = ufoRPop();
3709 const uint32_t b = ufoRPop();
3710 const uint32_t a = ufoRPop();
3711 ufoRPush(b); ufoRPush(c); ufoRPush(a);
3714 // RNROT
3715 // ( | a b c -- | c a b )
3716 UFWORD(RNROT) {
3717 const uint32_t c = ufoRPop();
3718 const uint32_t b = ufoRPop();
3719 const uint32_t a = ufoRPop();
3720 ufoRPush(c); ufoRPush(a); ufoRPush(b);
3724 // ////////////////////////////////////////////////////////////////////////// //
3725 // TIB API
3728 // REFILL
3729 // ( -- eofflag )
3730 UFWORD(REFILL) {
3731 ufoPushBool(ufoLoadNextLine(1));
3734 // REFILL-NOCROSS
3735 // ( -- eofflag )
3736 UFWORD(REFILL_NOCROSS) {
3737 ufoPushBool(ufoLoadNextLine(0));
3740 // (TIB-IN)
3741 // ( -- addr )
3742 UFWORD(TIB_IN) {
3743 ufoPush(ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx));
3746 // TIB-PEEKCH
3747 // ( -- char )
3748 UFWORD(TIB_PEEKCH) {
3749 ufoPush(ufoTibPeekCh());
3752 // TIB-PEEKCH-OFS
3753 // ( ofs -- char )
3754 UFWORD(TIB_PEEKCH_OFS) {
3755 const uint32_t ofs = ufoPop();
3756 ufoPush(ufoTibPeekChOfs(ofs));
3759 // TIB-GETCH
3760 // ( -- char )
3761 UFWORD(TIB_GETCH) {
3762 ufoPush(ufoTibGetCh());
3765 // TIB-SKIPCH
3766 // ( -- )
3767 UFWORD(TIB_SKIPCH) {
3768 ufoTibSkipCh();
3772 // ////////////////////////////////////////////////////////////////////////// //
3773 // TIB parsing
3776 //==========================================================================
3778 // ufoIsDelim
3780 //==========================================================================
3781 UFO_FORCE_INLINE int ufoIsDelim (uint8_t ch, uint8_t delim) {
3782 return (delim == 32 ? (ch <= 32) : (ch == delim));
3785 // (PARSE)
3786 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3787 // does base TIB parsing; never copies anything.
3788 // as our reader is line-based, returns FALSE on EOL.
3789 // EOL is detected after skipping leading delimiters.
3790 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3791 // trailing delimiter is always skipped.
3792 UFWORD(PAR_PARSE) {
3793 const uint32_t skipDelim = ufoPop();
3794 const uint32_t delim = ufoPop();
3795 uint8_t ch;
3797 if (delim == 0 || delim > 0xffU) {
3798 // skip everything
3799 while (ufoTibGetCh() != 0) {}
3800 ufoPushBool(0);
3801 } else {
3802 ch = ufoTibPeekCh();
3803 // skip initial delimiters
3804 if (skipDelim) {
3805 while (ch != 0 && ufoIsDelim(ch, delim)) {
3806 ufoTibSkipCh();
3807 ch = ufoTibPeekCh();
3810 if (ch == 0) {
3811 ufoPushBool(0);
3812 } else {
3813 // parse
3814 const uint32_t staddr = ufoImgGetU32(ufoAddrTIBx) + ufoImgGetU32(ufoAddrINx);
3815 uint32_t count = 0;
3816 while (ch != 0 && !ufoIsDelim(ch, delim)) {
3817 count += 1u;
3818 ufoTibSkipCh();
3819 ch = ufoTibPeekCh();
3821 // skip delimiter
3822 if (ch != 0) ufoTibSkipCh();
3823 ufoPush(staddr);
3824 ufoPush(count);
3825 ufoPushBool(1);
3830 // PARSE-SKIP-BLANKS
3831 // ( -- )
3832 UFWORD(PARSE_SKIP_BLANKS) {
3833 uint8_t ch = ufoTibPeekCh();
3834 while (ch != 0 && ch <= 32) {
3835 ufoTibSkipCh();
3836 ch = ufoTibPeekCh();
3840 //==========================================================================
3842 // ufoParseMLComment
3844 // initial two chars are skipped
3846 //==========================================================================
3847 static void ufoParseMLComment (uint32_t allowMulti, int nested) {
3848 uint32_t level = 1;
3849 uint8_t ch, ch1;
3850 while (level != 0) {
3851 ch = ufoTibGetCh();
3852 if (ch == 0) {
3853 if (allowMulti) {
3854 UFCALL(REFILL_NOCROSS);
3855 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3856 } else {
3857 ufoFatal("unexpected end of line in comment");
3859 } else {
3860 ch1 = ufoTibPeekCh();
3861 if (nested && ch == '(' && ch1 == '(') { ufoTibSkipCh(); level += 1; }
3862 else if (nested && ch == ')' && ch1 == ')') { ufoTibSkipCh(); level -= 1; }
3863 else if (!nested && ch == '*' && ch1 == ')') { ufo_assert(level == 1); ufoTibSkipCh(); level = 0; }
3868 // (PARSE-SKIP-COMMENTS)
3869 // ( allow-multiline? -- )
3870 // skip all blanks and comments
3871 UFWORD(PAR_PARSE_SKIP_COMMENTS) {
3872 const uint32_t allowMulti = ufoPop();
3873 uint8_t ch, ch1;
3874 ch = ufoTibPeekCh();
3875 #if 0
3876 fprintf(stderr, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch);
3877 #endif
3878 while (ch != 0) {
3879 if (ch <= 32) {
3880 ufoTibSkipCh();
3881 ch = ufoTibPeekCh();
3882 #if 0
3883 fprintf(stderr, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch);
3884 #endif
3885 } else if (ch == '(') {
3886 #if 0
3887 fprintf(stderr, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch, (char)ch1,
3888 ufoTibPeekChOfs(0));
3889 #endif
3890 ch1 = ufoTibPeekChOfs(1);
3891 if (ch1 <= 32) {
3892 // single-line comment
3893 do { ch = ufoTibGetCh(); } while (ch != 0 && ch != ')');
3894 ch = ufoTibPeekCh();
3895 } else if ((ch1 == '*' || ch1 == '(') && ufoTibPeekChOfs(2) <= 32) {
3896 // possibly multiline
3897 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3898 ufoParseMLComment(allowMulti, (ch1 == '('));
3899 ch = ufoTibPeekCh();
3900 } else {
3901 ch = 0;
3903 } else if (ch == '\\' && ufoTibPeekChOfs(1) <= 32) {
3904 // single-line comment
3905 while (ch != 0) ch = ufoTibGetCh();
3906 } else if (ch == '-' && ufoTibPeekChOfs(1) == ch && ufoTibPeekChOfs(2) <= 32) {
3907 // skip to EOL
3908 while (ch != 0) ch = ufoTibGetCh();
3909 } else if ((ch == ';' || ch == '/') && ufoTibPeekChOfs(1) == ch) {
3910 // skip to EOL
3911 while (ch != 0) ch = ufoTibGetCh();
3912 } else {
3913 ch = 0;
3916 #if 0
3917 fprintf(stderr, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3918 #endif
3921 // PARSE-SKIP-LINE
3922 // ( -- )
3923 UFWORD(PARSE_SKIP_LINE) {
3924 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE);
3925 if (ufoPop() != 0) {
3926 ufo2Drop();
3930 // PARSE-NAME
3931 // ( -- addr count )
3932 // parse with leading blanks skipping. doesn't copy anything.
3933 // return empty string on EOL.
3934 UFWORD(PARSE_NAME) {
3935 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE);
3936 if (ufoPop() == 0) {
3937 ufoPush(0);
3938 ufoPush(0);
3942 // PARSE
3943 // ( delim -- addr count TRUE / FALSE )
3944 // parse without skipping delimiters; never copies anything.
3945 // as our reader is line-based, returns FALSE on EOL.
3946 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3947 // trailing delimiter is always skipped.
3948 UFWORD(PARSE) {
3949 ufoPushBool(0); UFCALL(PAR_PARSE);
3953 // ////////////////////////////////////////////////////////////////////////// //
3954 // char output
3957 // (NORM-EMIT-CHAR)
3958 // ( ch -- )
3959 UFWORD(PAR_NORM_EMIT_CHAR) {
3960 uint32_t ch = ufoPop()&0xffU;
3961 if (ch < 32 || ch == 127) {
3962 if (ch != 9 && ch != 10 && ch != 13) ch = '?';
3964 ufoPush(ch);
3967 // (NORM-XEMIT-CHAR)
3968 // ( ch -- )
3969 UFWORD(PAR_NORM_XEMIT_CHAR) {
3970 uint32_t ch = ufoPop()&0xffU;
3971 if (ch < 32 || ch == 127) ch = '?';
3972 ufoPush(ch);
3975 // (EMIT)
3976 // ( n -- )
3977 UFWORD(PAR_EMIT) {
3978 uint32_t ch = ufoPop()&0xffU;
3979 ufoLastEmitWasCR = (ch == 10);
3980 putchar((char)ch);
3983 // LASTCR?
3984 // ( -- bool )
3985 UFWORD(LASTCRQ) {
3986 ufoPushBool(ufoLastEmitWasCR);
3989 // LASTCR!
3990 // ( bool -- )
3991 UFWORD(LASTCRSET) {
3992 ufoLastEmitWasCR = !!ufoPop();
3995 // FLUSH-EMIT
3996 // ( -- )
3997 UFWORD(FLUSH_EMIT) {
3998 ufoFlushOutput();
4002 // ////////////////////////////////////////////////////////////////////////// //
4003 // simple math
4006 #define UF_UMATH(name_,op_) \
4007 UFWORD(name_) { \
4008 const uint32_t a = ufoPop(); \
4009 ufoPush(op_); \
4012 #define UF_BMATH(name_,op_) \
4013 UFWORD(name_) { \
4014 const uint32_t b = ufoPop(); \
4015 const uint32_t a = ufoPop(); \
4016 ufoPush(op_); \
4019 #define UF_BDIV(name_,op_) \
4020 UFWORD(name_) { \
4021 const uint32_t b = ufoPop(); \
4022 const uint32_t a = ufoPop(); \
4023 if (b == 0) ufoFatal("division by zero"); \
4024 ufoPush(op_); \
4027 #define UFO_POP_U64() ({ \
4028 const uint32_t hi_ = ufoPop(); \
4029 const uint32_t lo_ = ufoPop(); \
4030 (((uint64_t)hi_ << 32) | lo_); \
4033 // this is UB by the idiotic C standard. i don't care.
4034 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
4036 #define UFO_PUSH_U64(vn_) do { \
4037 ufoPush((uint32_t)(vn_)); \
4038 ufoPush((uint32_t)((vn_) >> 32)); \
4039 } while (0)
4041 // this is UB by the idiotic C standard. i don't care.
4042 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
4044 // +
4045 // ( a b -- a+b )
4046 UF_BMATH(PLUS, a + b);
4048 // -
4049 // ( a b -- a-b )
4050 UF_BMATH(MINUS, a - b);
4052 // *
4053 // ( a b -- a*b )
4054 UF_BMATH(MUL, (uint32_t)((int32_t)a * (int32_t)b));
4056 // U*
4057 // ( a b -- a*b )
4058 UF_BMATH(UMUL, a * b);
4060 // /
4061 // ( a b -- a/b )
4062 UF_BDIV(DIV, (uint32_t)((int32_t)a / (int32_t)b));
4064 // U/
4065 // ( a b -- a/b )
4066 UF_BDIV(UDIV, a / b);
4068 // MOD
4069 // ( a b -- a%b )
4070 UF_BDIV(MOD, (uint32_t)((int32_t)a % (int32_t)b));
4072 // UMOD
4073 // ( a b -- a%b )
4074 UF_BDIV(UMOD, a % b);
4076 // /MOD
4077 // ( a b -- a/b, a%b )
4078 UFWORD(DIVMOD) {
4079 const int32_t b = (int32_t)ufoPop();
4080 const int32_t a = (int32_t)ufoPop();
4081 if (b == 0) ufoFatal("division by zero");
4082 ufoPush((uint32_t)(a/b));
4083 ufoPush((uint32_t)(a%b));
4086 // U/MOD
4087 // ( a b -- a/b, a%b )
4088 UFWORD(UDIVMOD) {
4089 const uint32_t b = ufoPop();
4090 const uint32_t a = ufoPop();
4091 if (b == 0) ufoFatal("division by zero");
4092 ufoPush((uint32_t)(a/b));
4093 ufoPush((uint32_t)(a%b));
4096 // */
4097 // ( a b c -- a*b/c )
4098 // this uses 64-bit intermediate value
4099 UFWORD(MULDIV) {
4100 const int32_t c = (int32_t)ufoPop();
4101 const int32_t b = (int32_t)ufoPop();
4102 const int32_t a = (int32_t)ufoPop();
4103 if (c == 0) ufoFatal("division by zero");
4104 int64_t xval = a; xval *= b; xval /= c;
4105 ufoPush((uint32_t)(int32_t)xval);
4108 // U*/
4109 // ( a b c -- a*b/c )
4110 // this uses 64-bit intermediate value
4111 UFWORD(UMULDIV) {
4112 const uint32_t c = ufoPop();
4113 const uint32_t b = ufoPop();
4114 const uint32_t a = ufoPop();
4115 if (c == 0) ufoFatal("division by zero");
4116 uint64_t xval = a; xval *= b; xval /= c;
4117 ufoPush((uint32_t)xval);
4120 // */MOD
4121 // ( a b c -- a*b/c a*b%c )
4122 // this uses 64-bit intermediate value
4123 UFWORD(MULDIVMOD) {
4124 const int32_t c = (int32_t)ufoPop();
4125 const int32_t b = (int32_t)ufoPop();
4126 const int32_t a = (int32_t)ufoPop();
4127 if (c == 0) ufoFatal("division by zero");
4128 int64_t xval = a; xval *= b;
4129 ufoPush((uint32_t)(int32_t)(xval / c));
4130 ufoPush((uint32_t)(int32_t)(xval % c));
4133 // U*/
4134 // ( a b c -- a*b/c )
4135 // this uses 64-bit intermediate value
4136 UFWORD(UMULDIVMOD) {
4137 const uint32_t c = ufoPop();
4138 const uint32_t b = ufoPop();
4139 const uint32_t a = ufoPop();
4140 if (c == 0) ufoFatal("division by zero");
4141 uint64_t xval = a; xval *= b;
4142 ufoPush((uint32_t)(xval / c));
4143 ufoPush((uint32_t)(xval % c));
4146 // M*
4147 // ( a b -- lo(a*b) hi(a*b) )
4148 // this leaves 64-bit result
4149 UFWORD(MMUL) {
4150 const int32_t b = (int32_t)ufoPop();
4151 const int32_t a = (int32_t)ufoPop();
4152 int64_t xval = a; xval *= b;
4153 UFO_PUSH_I64(xval);
4156 // UM*
4157 // ( a b -- lo(a*b) hi(a*b) )
4158 // this leaves 64-bit result
4159 UFWORD(UMMUL) {
4160 const uint32_t b = ufoPop();
4161 const uint32_t a = ufoPop();
4162 uint64_t xval = a; xval *= b;
4163 UFO_PUSH_U64(xval);
4166 // M/MOD
4167 // ( alo ahi b -- a/b a%b )
4168 UFWORD(MDIVMOD) {
4169 const int32_t b = (int32_t)ufoPop();
4170 if (b == 0) ufoFatal("division by zero");
4171 int64_t a = UFO_POP_I64();
4172 int32_t adiv = (int32_t)(a / b);
4173 int32_t amod = (int32_t)(a % b);
4174 ufoPush((uint32_t)adiv);
4175 ufoPush((uint32_t)amod);
4178 // UM/MOD
4179 // ( alo ahi b -- a/b a%b )
4180 UFWORD(UMDIVMOD) {
4181 const uint32_t b = ufoPop();
4182 if (b == 0) ufoFatal("division by zero");
4183 uint64_t a = UFO_POP_U64();
4184 uint32_t adiv = (uint32_t)(a / b);
4185 uint32_t amod = (uint32_t)(a % b);
4186 ufoPush(adiv);
4187 ufoPush(amod);
4190 // UDS*
4191 // ( alo ahi u -- lo hi )
4192 UFWORD(UDSMUL) {
4193 const uint32_t b = ufoPop();
4194 uint64_t a = UFO_POP_U64();
4195 a *= b;
4196 UFO_PUSH_U64(a);
4199 // D-
4200 // ( lo0 hi0 lo1 hi1 -- lo hi )
4201 UFWORD(DMINUS) {
4202 uint64_t n1 = UFO_POP_U64();
4203 uint64_t n0 = UFO_POP_U64();
4204 n0 -= n1;
4205 UFO_PUSH_U64(n0);
4208 // D+
4209 // ( lo0 hi0 lo1 hi1 -- lo hi )
4210 UFWORD(DPLUS) {
4211 uint64_t n1 = UFO_POP_U64();
4212 uint64_t n0 = UFO_POP_U64();
4213 n0 += n1;
4214 UFO_PUSH_U64(n0);
4217 // D=
4218 // ( lo0 hi0 lo1 hi1 -- bool )
4219 UFWORD(DEQU) {
4220 uint64_t n1 = UFO_POP_U64();
4221 uint64_t n0 = UFO_POP_U64();
4222 ufoPushBool(n0 == n1);
4225 // D<
4226 // ( lo0 hi0 lo1 hi1 -- bool )
4227 UFWORD(DLESS) {
4228 int64_t n1 = UFO_POP_I64();
4229 int64_t n0 = UFO_POP_I64();
4230 ufoPushBool(n0 < n1);
4233 // D<=
4234 // ( lo0 hi0 lo1 hi1 -- bool )
4235 UFWORD(DLESSEQU) {
4236 int64_t n1 = UFO_POP_I64();
4237 int64_t n0 = UFO_POP_I64();
4238 ufoPushBool(n0 <= n1);
4241 // DU<
4242 // ( lo0 hi0 lo1 hi1 -- bool )
4243 UFWORD(DULESS) {
4244 uint64_t n1 = UFO_POP_U64();
4245 uint64_t n0 = UFO_POP_U64();
4246 ufoPushBool(n0 < n1);
4249 // DU<=
4250 // ( lo0 hi0 lo1 hi1 -- bool )
4251 UFWORD(DULESSEQU) {
4252 uint64_t n1 = UFO_POP_U64();
4253 uint64_t n0 = UFO_POP_U64();
4254 ufoPushBool(n0 <= n1);
4257 // SM/REM
4258 // ( dlo dhi n -- nmod ndiv )
4259 // rounds toward zero
4260 UFWORD(SMREM) {
4261 const int32_t n = (int32_t)ufoPop();
4262 if (n == 0) ufoFatal("division by zero");
4263 int64_t d = UFO_POP_I64();
4264 int32_t ndiv = (int32_t)(d / n);
4265 int32_t nmod = (int32_t)(d % n);
4266 ufoPush(nmod);
4267 ufoPush(ndiv);
4270 // FM/MOD
4271 // ( dlo dhi n -- nmod ndiv )
4272 // rounds toward negative infinity
4273 UFWORD(FMMOD) {
4274 const int32_t n = (int32_t)ufoPop();
4275 if (n == 0) ufoFatal("division by zero");
4276 int64_t d = UFO_POP_I64();
4277 int32_t ndiv = (int32_t)(d / n);
4278 int32_t nmod = (int32_t)(d % n);
4279 if (nmod != 0 && ((uint32_t)n ^ (uint32_t)(d >> 32)) >= 0x80000000u) {
4280 ndiv -= 1;
4281 nmod += n;
4283 ufoPush(nmod);
4284 ufoPush(ndiv);
4288 // ////////////////////////////////////////////////////////////////////////// //
4289 // simple logic and bit manipulation
4292 #define UF_CMP(name_,op_) \
4293 UFWORD(name_) { \
4294 const uint32_t b = ufoPop(); \
4295 const uint32_t a = ufoPop(); \
4296 ufoPushBool(op_); \
4299 // <
4300 // ( a b -- a<b )
4301 UF_CMP(LESS, (int32_t)a < (int32_t)b);
4303 // U<
4304 // ( a b -- a<b )
4305 UF_CMP(ULESS, a < b);
4307 // >
4308 // ( a b -- a>b )
4309 UF_CMP(GREAT, (int32_t)a > (int32_t)b);
4311 // U>
4312 // ( a b -- a>b )
4313 UF_CMP(UGREAT, a > b);
4315 // <=
4316 // ( a b -- a<=b )
4317 UF_CMP(LESSEQU, (int32_t)a <= (int32_t)b);
4319 // U<=
4320 // ( a b -- a<=b )
4321 UF_CMP(ULESSEQU, a <= b);
4323 // >=
4324 // ( a b -- a>=b )
4325 UF_CMP(GREATEQU, (int32_t)a >= (int32_t)b);
4327 // U>=
4328 // ( a b -- a>=b )
4329 UF_CMP(UGREATEQU, a >= b);
4331 // =
4332 // ( a b -- a=b )
4333 UF_CMP(EQU, a == b);
4335 // <>
4336 // ( a b -- a<>b )
4337 UF_CMP(NOTEQU, a != b);
4339 // 0=
4340 // ( a -- a==0 )
4341 UFWORD(ZERO_EQU) {
4342 const uint32_t a = ufoPop();
4343 ufoPushBool(a == 0);
4346 // 0<>
4347 // ( a -- a<>0 )
4348 UFWORD(ZERO_NOTEQU) {
4349 const uint32_t a = ufoPop();
4350 ufoPushBool(a != 0);
4353 // LAND
4354 // ( a b -- a&&b )
4355 UF_CMP(LOGAND, a && b);
4357 // LOR
4358 // ( a b -- a||b )
4359 UF_CMP(LOGOR, a || b);
4361 // AND
4362 // ( a b -- a&b )
4363 UFWORD(AND) {
4364 const uint32_t b = ufoPop();
4365 const uint32_t a = ufoPop();
4366 ufoPush(a&b);
4369 // OR
4370 // ( a b -- a|b )
4371 UFWORD(OR) {
4372 const uint32_t b = ufoPop();
4373 const uint32_t a = ufoPop();
4374 ufoPush(a|b);
4377 // XOR
4378 // ( a b -- a^b )
4379 UFWORD(XOR) {
4380 const uint32_t b = ufoPop();
4381 const uint32_t a = ufoPop();
4382 ufoPush(a^b);
4385 // BITNOT
4386 // ( a -- ~a )
4387 UFWORD(BITNOT) {
4388 const uint32_t a = ufoPop();
4389 ufoPush(~a);
4392 // ASH
4393 // ( n count -- )
4394 // arithmetic shift; positive `n` shifts to the left
4395 UFWORD(ASH) {
4396 int32_t c = (int32_t)ufoPop();
4397 if (c < 0) {
4398 // right
4399 int32_t n = (int32_t)ufoPop();
4400 if (c < -30) {
4401 if (n < 0) n = -1; else n = 0;
4402 } else {
4403 n >>= (uint8_t)(-c);
4405 ufoPush((uint32_t)n);
4406 } else if (c > 0) {
4407 // left
4408 uint32_t u = ufoPop();
4409 if (c > 31) {
4410 u = 0;
4411 } else {
4412 u <<= (uint8_t)c;
4414 ufoPush(u);
4418 // LSH
4419 // ( n count -- )
4420 // logical shift; positive `n` shifts to the left
4421 UFWORD(LSH) {
4422 int32_t c = (int32_t) ufoPop();
4423 uint32_t u = ufoPop();
4424 if (c < 0) {
4425 // right
4426 if (c < -31) {
4427 u = 0;
4428 } else {
4429 u >>= (uint8_t)(-c);
4431 } else if (c > 0) {
4432 // left
4433 if (c > 31) {
4434 u = 0;
4435 } else {
4436 u <<= (uint8_t)c;
4439 ufoPush(u);
4443 // ////////////////////////////////////////////////////////////////////////// //
4444 // string unescaping
4447 // (UNESCAPE)
4448 // ( addr count -- addr count )
4449 UFWORD(PAR_UNESCAPE) {
4450 const uint32_t count = ufoPop();
4451 const uint32_t addr = ufoPeek();
4452 if ((count & ((uint32_t)1<<31)) == 0) {
4453 const uint32_t eaddr = addr + count;
4454 uint32_t caddr = addr;
4455 uint32_t daddr = addr;
4456 while (caddr != eaddr) {
4457 uint8_t ch = ufoImgGetU8Ext(caddr); caddr += 1u;
4458 if (ch == '\\' && caddr != eaddr) {
4459 ch = ufoImgGetU8Ext(caddr); caddr += 1u;
4460 switch (ch) {
4461 case 'r': ch = '\r'; break;
4462 case 'n': ch = '\n'; break;
4463 case 't': ch = '\t'; break;
4464 case 'e': ch = '\x1b'; break;
4465 case '`': ch = '"'; break; // special escape to insert double-quote
4466 case '"': ch = '"'; break;
4467 case '\\': ch = '\\'; break;
4468 case 'x': case 'X':
4469 if (eaddr - daddr >= 1) {
4470 const int dg0 = digitInBase((char)(ufoImgGetU8Ext(caddr)), 16);
4471 if (dg0 < 0) ufoFatal("invalid hex string escape");
4472 if (eaddr - daddr >= 2) {
4473 const int dg1 = digitInBase((char)(ufoImgGetU8Ext(caddr + 1u)), 16);
4474 if (dg1 < 0) ufoFatal("invalid hex string escape");
4475 ch = (uint8_t)(dg0 * 16 + dg1);
4476 caddr += 2u;
4477 } else {
4478 ch = (uint8_t)dg0;
4479 caddr += 1u;
4481 } else {
4482 ufoFatal("invalid hex string escape");
4484 break;
4485 default: ufoFatal("invalid string escape");
4488 ufoImgPutU8Ext(daddr, ch); daddr += 1u;
4490 ufoPush(daddr - addr);
4491 } else {
4492 ufoPush(count);
4497 // ////////////////////////////////////////////////////////////////////////// //
4498 // numeric conversions
4501 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4502 UFWORD(PAR_BASED_NUMBER) {
4503 const uint32_t xbase = ufoPop();
4504 const uint32_t allowSign = ufoPop();
4505 int32_t count = (int32_t)ufoPop();
4506 uint32_t addr = ufoPop();
4507 uint32_t n = 0;
4508 int base = 0;
4509 int neg = 0;
4510 uint8_t ch;
4512 if (allowSign && count > 1) {
4513 ch = ufoImgGetU8Ext(addr);
4514 if (ch == '-') { neg = 1; addr += 1u; count -= 1; }
4515 else if (ch == '+') { neg = 0; addr += 1u; count -= 1; }
4518 // special-based numbers
4519 ch = ufoImgGetU8Ext(addr);
4520 if (count >= 3 && ch == '0') {
4521 switch (ufoImgGetU8Ext(addr + 1u)) {
4522 case 'x': case 'X': base = 16; break;
4523 case 'o': case 'O': base = 8; break;
4524 case 'b': case 'B': base = 2; break;
4525 case 'd': case 'D': base = 10; break;
4526 default: break;
4528 if (base && digitInBase((char)ufoImgGetU8Ext(addr + (uint32_t)count - 1u), base) >= 0) {
4529 addr += 2; count -= 2;
4530 } else {
4531 base = 0;
4533 } else if (count >= 2 && ch == '$') {
4534 base = 16;
4535 addr += 1u; count -= 1;
4536 } else if (count >= 2 && ch == '#') {
4537 base = 16;
4538 addr += 1u; count -= 1;
4539 } else if (count >= 2 && ch == '%') {
4540 base = 2;
4541 addr += 1u; count -= 1;
4542 } else if (count >= 3 && ch == '&') {
4543 switch (ufoImgGetU8Ext(addr + 1u)) {
4544 case 'h': case 'H': base = 16; break;
4545 case 'o': case 'O': base = 8; break;
4546 case 'b': case 'B': base = 2; break;
4547 case 'd': case 'D': base = 10; break;
4548 default: break;
4550 if (base) { addr += 2u; count -= 2; }
4552 if (!base && count > 2 && ch >= '0' && ch <= '9') {
4553 ch = ufoImgGetU8Ext(addr + (uint32_t)count - 1u);
4554 switch (ch) {
4555 case 'b': case 'B': if (xbase < 12) base = 2; break;
4556 case 'o': case 'O': if (xbase < 25) base = 8; break;
4557 case 'h': case 'H': if (xbase < 18) base = 16; break;
4559 if (base) count -= 1;
4562 // in current base?
4563 if (!base && xbase < 255) base = xbase;
4565 if (count <= 0 || base < 1 || base > 36) {
4566 ufoPushBool(0);
4567 } else {
4568 uint32_t nc;
4569 int wasDig = 0, wasUnder = 1, error = 0, dig;
4570 while (!error && count != 0) {
4571 ch = ufoImgGetU8Ext(addr); addr += 1u; count -= 1;
4572 if (ch != '_') {
4573 error = 1; wasUnder = 0; wasDig = 1;
4574 dig = digitInBase((char)ch, (int)base);
4575 if (dig >= 0) {
4576 nc = n * (uint32_t)base;
4577 if (nc >= n) {
4578 nc += (uint32_t)dig;
4579 if (nc >= n) {
4580 n = nc;
4581 error = 0;
4585 } else {
4586 error = wasUnder;
4587 wasUnder = 1;
4591 if (!error && wasDig && !wasUnder) {
4592 if (allowSign && neg) n = ~n + 1u;
4593 ufoPush(n);
4594 ufoPushBool(1);
4595 } else {
4596 ufoPushBool(0);
4602 // ////////////////////////////////////////////////////////////////////////// //
4603 // compiler-related, dictionary-related
4606 static char ufoWNameBuf[256];
4608 // (CREATE-WORD-HEADER)
4609 // ( addr count word-flags -- )
4610 UFWORD(PAR_CREATE_WORD_HEADER) {
4611 const uint32_t flags = ufoPop();
4612 const uint32_t wlen = ufoPop();
4613 const uint32_t waddr = ufoPop();
4614 if (wlen == 0) ufoFatal("word name expected");
4615 if (wlen >= UFO_MAX_WORD_LENGTH) ufoFatal("word name too long");
4616 // copy to separate buffer
4617 for (uint32_t f = 0; f < wlen; f += 1) {
4618 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4620 ufoWNameBuf[wlen] = 0;
4621 ufoCreateWordHeader(ufoWNameBuf, flags);
4624 // (CREATE-NAMELESS-WORD-HEADER)
4625 // ( word-flags -- )
4626 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER) {
4627 const uint32_t flags = ufoPop();
4628 ufoCreateWordHeader("", flags);
4631 // FIND-WORD
4632 // ( addr count -- cfa TRUE / FALSE)
4633 UFWORD(FIND_WORD) {
4634 const uint32_t wlen = ufoPop();
4635 const uint32_t waddr = ufoPop();
4636 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4637 // copy to separate buffer
4638 for (uint32_t f = 0; f < wlen; f += 1) {
4639 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4641 ufoWNameBuf[wlen] = 0;
4642 const uint32_t cfa = ufoFindWord(ufoWNameBuf);
4643 if (cfa != 0) {
4644 ufoPush(cfa);
4645 ufoPushBool(1);
4646 } else {
4647 ufoPushBool(0);
4649 } else {
4650 ufoPushBool(0);
4654 // (FIND-WORD-IN-VOC)
4655 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4656 // find only in the given voc; no name resolution
4657 UFWORD(FIND_WORD_IN_VOC) {
4658 const uint32_t allowHidden = ufoPop();
4659 const uint32_t vocid = ufoPop();
4660 const uint32_t wlen = ufoPop();
4661 const uint32_t waddr = ufoPop();
4662 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4663 // copy to separate buffer
4664 for (uint32_t f = 0; f < wlen; f += 1) {
4665 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4667 ufoWNameBuf[wlen] = 0;
4668 const uint32_t cfa = ufoFindWordInVoc(ufoWNameBuf, wlen, 0, vocid, (allowHidden ? 1 : 0));
4669 if (cfa != 0) {
4670 ufoPush(cfa);
4671 ufoPushBool(1);
4672 } else {
4673 ufoPushBool(0);
4675 } else {
4676 ufoPushBool(0);
4680 // (FIND-WORD-IN-VOC-AND-PARENTS)
4681 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4682 // find only in the given voc; no name resolution
4683 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS) {
4684 const uint32_t allowHidden = ufoPop();
4685 const uint32_t vocid = ufoPop();
4686 const uint32_t wlen = ufoPop();
4687 const uint32_t waddr = ufoPop();
4688 if (wlen > 0 && wlen < UFO_MAX_WORD_LENGTH) {
4689 // copy to separate buffer
4690 for (uint32_t f = 0; f < wlen; f += 1) {
4691 ufoWNameBuf[f] = (char)ufoImgGetU8Ext(waddr + f);
4693 ufoWNameBuf[wlen] = 0;
4694 const uint32_t cfa = ufoFindWordInVocAndParents(ufoWNameBuf, wlen, 0, vocid, (allowHidden ? 1 : 0));
4695 if (cfa != 0) {
4696 ufoPush(cfa);
4697 ufoPushBool(1);
4698 } else {
4699 ufoPushBool(0);
4701 } else {
4702 ufoPushBool(0);
4707 // ////////////////////////////////////////////////////////////////////////// //
4708 // more compiler words
4711 // ////////////////////////////////////////////////////////////////////////// //
4712 // vocabulary and wordlist utilities
4715 // (VSP@)
4716 // ( -- vsp )
4717 UFWORD(PAR_GET_VSP) {
4718 ufoPush(ufoVSP);
4721 // (VSP!)
4722 // ( vsp -- )
4723 UFWORD(PAR_SET_VSP) {
4724 const uint32_t vsp = ufoPop();
4725 if (vsp > UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4726 ufoVSP = vsp;
4729 // (VSP-AT@)
4730 // ( idx -- value )
4731 UFWORD(PAR_VSP_LOAD) {
4732 const uint32_t vsp = ufoPop();
4733 if (vsp >= UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4734 ufoPush(ufoVocStack[vsp]);
4737 // (VSP-AT!)
4738 // ( value idx -- )
4739 UFWORD(PAR_VSP_STORE) {
4740 const uint32_t vsp = ufoPop();
4741 const uint32_t value = ufoPop();
4742 if (vsp >= UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
4743 ufoVocStack[vsp] = value;
4747 // ////////////////////////////////////////////////////////////////////////// //
4748 // word field address conversion
4751 // CFA->PFA
4752 // ( cfa -- pfa )
4753 UFWORD(CFA2PFA) {
4754 const uint32_t cfa = ufoPop();
4755 ufoPush(UFO_CFA_TO_PFA(cfa));
4758 // CFA->NFA
4759 // ( cfa -- nfa )
4760 UFWORD(CFA2NFA) {
4761 const uint32_t cfa = ufoPop();
4762 ufoPush(UFO_CFA_TO_NFA(cfa));
4765 // CFA->LFA
4766 // ( cfa -- lfa )
4767 UFWORD(CFA2LFA) {
4768 const uint32_t cfa = ufoPop();
4769 ufoPush(UFO_CFA_TO_LFA(cfa));
4772 // CFA->WEND
4773 // ( cfa -- wend-addr )
4774 UFWORD(CFA2WEND) {
4775 const uint32_t cfa = ufoPop();
4776 ufoPush(ufoGetWordEndAddr(cfa));
4779 // PFA->CFA
4780 // ( pfa -- cfa )
4781 UFWORD(PFA2CFA) {
4782 const uint32_t pfa = ufoPop();
4783 ufoPush(UFO_PFA_TO_CFA(pfa));
4786 // PFA->NFA
4787 // ( pfa -- nfa )
4788 UFWORD(PFA2NFA) {
4789 const uint32_t pfa = ufoPop();
4790 const uint32_t cfa = UFO_PFA_TO_CFA(pfa);
4791 ufoPush(UFO_CFA_TO_NFA(cfa));
4794 // NFA->CFA
4795 // ( nfa -- cfa )
4796 UFWORD(NFA2CFA) {
4797 const uint32_t nfa = ufoPop();
4798 ufoPush(UFO_NFA_TO_CFA(nfa));
4801 // NFA->PFA
4802 // ( nfa -- pfa )
4803 UFWORD(NFA2PFA) {
4804 const uint32_t nfa = ufoPop();
4805 const uint32_t cfa = UFO_NFA_TO_CFA(nfa);
4806 ufoPush(UFO_CFA_TO_PFA(cfa));
4809 // NFA->LFA
4810 // ( nfa -- lfa )
4811 UFWORD(NFA2LFA) {
4812 const uint32_t nfa = ufoPop();
4813 ufoPush(UFO_NFA_TO_LFA(nfa));
4816 // LFA->CFA
4817 // ( lfa -- cfa )
4818 UFWORD(LFA2CFA) {
4819 const uint32_t lfa = ufoPop();
4820 ufoPush(UFO_LFA_TO_CFA(lfa));
4823 // LFA->PFA
4824 // ( lfa -- pfa )
4825 UFWORD(LFA2PFA) {
4826 const uint32_t lfa = ufoPop();
4827 const uint32_t cfa = UFO_LFA_TO_CFA(lfa);
4828 ufoPush(UFO_CFA_TO_PFA(cfa));
4831 // LFA->BFA
4832 // ( lfa -- bfa )
4833 UFWORD(LFA2BFA) {
4834 const uint32_t lfa = ufoPop();
4835 ufoPush(UFO_LFA_TO_BFA(lfa));
4838 // LFA->XFA
4839 // ( lfa -- xfa )
4840 UFWORD(LFA2XFA) {
4841 const uint32_t lfa = ufoPop();
4842 ufoPush(UFO_LFA_TO_XFA(lfa));
4845 // LFA->YFA
4846 // ( lfa -- yfa )
4847 UFWORD(LFA2YFA) {
4848 const uint32_t lfa = ufoPop();
4849 ufoPush(UFO_LFA_TO_YFA(lfa));
4852 // LFA->NFA
4853 // ( lfa -- nfa )
4854 UFWORD(LFA2NFA) {
4855 const uint32_t lfa = ufoPop();
4856 ufoPush(UFO_LFA_TO_NFA(lfa));
4859 // IP->NFA
4860 // ( ip -- nfa / 0 )
4861 UFWORD(IP2NFA) {
4862 const uint32_t ip = ufoPop();
4863 ufoPush(ufoFindWordForIP(ip));
4866 // IP->FILE/LINE
4867 // ( ip -- addr count line TRUE / FALSE )
4868 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4869 UFWORD(IP2FILELINE) {
4870 const uint32_t ip = ufoPop();
4871 uint32_t fline;
4872 const char *fname = ufoFindFileForIP(ip, &fline, NULL, NULL);
4873 if (fname != NULL) {
4874 UFCALL(PAD);
4875 uint32_t addr = ufoPeek();
4876 uint32_t count = 0;
4877 while (*fname != 0) {
4878 ufoImgPutU8(addr, *(const unsigned char *)fname);
4879 fname += 1u; addr += 1u; count += 1u;
4881 ufoImgPutU8(addr, 0); // just in case
4882 ufoPush(count);
4883 ufoPush(fline);
4884 ufoPushBool(1);
4885 } else {
4886 ufoPushBool(0);
4891 // IP->FILE-HASH/LINE
4892 // ( ip -- len hash line TRUE / FALSE )
4893 UFWORD(IP2FILEHASHLINE) {
4894 const uint32_t ip = ufoPop();
4895 uint32_t fline, fhash, flen;
4896 const char *fname = ufoFindFileForIP(ip, &fline, &flen, &fhash);
4897 if (fname != NULL) {
4898 ufoPush(flen);
4899 ufoPush(fhash);
4900 ufoPush(fline);
4901 ufoPushBool(1);
4902 } else {
4903 ufoPushBool(0);
4908 // ////////////////////////////////////////////////////////////////////////// //
4909 // string operations
4912 UFO_FORCE_INLINE uint32_t ufoHashBuf (uint32_t addr, uint32_t size, uint8_t orbyte) {
4913 uint32_t hash = 0x29a;
4914 if ((size & ((uint32_t)1<<31)) == 0) {
4915 while (size != 0) {
4916 hash += ufoImgGetU8Ext(addr) | orbyte;
4917 hash += hash<<10;
4918 hash ^= hash>>6;
4919 addr += 1u; size -= 1u;
4922 // finalize
4923 hash += hash<<3;
4924 hash ^= hash>>11;
4925 hash += hash<<15;
4926 return hash;
4929 //==========================================================================
4931 // ufoBufEqu
4933 //==========================================================================
4934 UFO_FORCE_INLINE int ufoBufEqu (uint32_t addr0, uint32_t addr1, uint32_t count) {
4935 int res;
4936 if ((count & ((uint32_t)1<<31)) == 0) {
4937 res = 1;
4938 while (res != 0 && count != 0) {
4939 res = (toUpperU8(ufoImgGetU8Ext(addr0)) == toUpperU8(ufoImgGetU8Ext(addr1)));
4940 addr0 += 1u; addr1 += 1u; count -= 1u;
4942 } else {
4943 res = 0;
4945 return res;
4948 // STRING:=
4949 // ( a0 c0 a1 c1 -- bool )
4950 UFWORD(STREQU) {
4951 int32_t c1 = (int32_t)ufoPop();
4952 uint32_t a1 = ufoPop();
4953 int32_t c0 = (int32_t)ufoPop();
4954 uint32_t a0 = ufoPop();
4955 if (c0 < 0) c0 = 0;
4956 if (c1 < 0) c1 = 0;
4957 if (c0 == c1) {
4958 int res = 1;
4959 while (res != 0 && c0 != 0) {
4960 res = (ufoImgGetU8Ext(a0) == ufoImgGetU8Ext(a1));
4961 a0 += 1; a1 += 1; c0 -= 1;
4963 ufoPushBool(res);
4964 } else {
4965 ufoPushBool(0);
4969 // STRING:=CI
4970 // ( a0 c0 a1 c1 -- bool )
4971 UFWORD(STREQUCI) {
4972 int32_t c1 = (int32_t)ufoPop();
4973 uint32_t a1 = ufoPop();
4974 int32_t c0 = (int32_t)ufoPop();
4975 uint32_t a0 = ufoPop();
4976 if (c0 < 0) c0 = 0;
4977 if (c1 < 0) c1 = 0;
4978 if (c0 == c1) {
4979 int res = 1;
4980 while (res != 0 && c0 != 0) {
4981 res = (toUpperU8(ufoImgGetU8Ext(a0)) == toUpperU8(ufoImgGetU8Ext(a1)));
4982 a0 += 1; a1 += 1; c0 -= 1;
4984 ufoPushBool(res);
4985 } else {
4986 ufoPushBool(0);
4990 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4991 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4992 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4993 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4994 UFWORD(SEARCH) {
4995 const uint32_t pcount = ufoPop();
4996 const uint32_t paddr = ufoPop();
4997 const uint32_t tcount = ufoPop();
4998 const uint32_t taddr = ufoPop();
4999 if ((pcount & ((uint32_t)1 << 31)) == 0 && (tcount & ((uint32_t)1 << 31)) == 0) {
5000 for (uint32_t f = 0; tcount - f >= pcount; f += 1) {
5001 if (ufoBufEqu(taddr + f, paddr, pcount)) {
5002 ufoPush(taddr + f);
5003 ufoPush(tcount - f);
5004 ufoPushBool(1);
5005 return;
5009 ufoPush(taddr);
5010 ufoPush(tcount);
5011 ufoPushBool(0);
5014 // STRING:HASH
5015 // ( addr count -- hash )
5016 UFWORD(STRHASH) {
5017 uint32_t count = ufoPop();
5018 uint32_t addr = ufoPop();
5019 ufoPush(ufoHashBuf(addr, count, 0));
5022 // STRING:HASH-CI
5023 // ( addr count -- hash )
5024 UFWORD(STRHASHCI) {
5025 uint32_t count = ufoPop();
5026 uint32_t addr = ufoPop();
5027 ufoPush(ufoHashBuf(addr, count, 0x20));
5031 // ////////////////////////////////////////////////////////////////////////// //
5032 // conditional defines
5035 typedef struct UForthCondDefine_t UForthCondDefine;
5036 struct UForthCondDefine_t {
5037 char *name;
5038 uint32_t namelen;
5039 uint32_t hash;
5040 UForthCondDefine *next;
5043 static UForthCondDefine *ufoCondDefines = NULL;
5044 static char ufoErrMsgBuf[4096];
5047 //==========================================================================
5049 // ufoStrEquCI
5051 //==========================================================================
5052 UFO_DISABLE_INLINE int ufoStrEquCI (const void *str0, const void *str1) {
5053 const unsigned char *s0 = (const unsigned char *)str0;
5054 const unsigned char *s1 = (const unsigned char *)str1;
5055 while (*s0 && *s1) {
5056 if (toUpperU8(*s0) != toUpperU8(*s1)) return 0;
5057 s0 += 1; s1 += 1;
5059 return (*s0 == 0 && *s1 == 0);
5063 //==========================================================================
5065 // ufoBufEquCI
5067 //==========================================================================
5068 UFO_FORCE_INLINE int ufoBufEquCI (uint32_t addr, uint32_t count, const void *buf) {
5069 int res;
5070 if ((count & ((uint32_t)1<<31)) == 0) {
5071 const unsigned char *src = (const unsigned char *)buf;
5072 res = 1;
5073 while (res != 0 && count != 0) {
5074 res = (toUpperU8(*src) == toUpperU8(ufoImgGetU8Ext(addr)));
5075 src += 1; addr += 1u; count -= 1u;
5077 } else {
5078 res = 0;
5080 return res;
5084 //==========================================================================
5086 // ufoClearCondDefines
5088 //==========================================================================
5089 static void ufoClearCondDefines (void) {
5090 while (ufoCondDefines) {
5091 UForthCondDefine *df = ufoCondDefines;
5092 ufoCondDefines = df->next;
5093 if (df->name) free(df->name);
5094 free(df);
5099 //==========================================================================
5101 // ufoHasCondDefine
5103 //==========================================================================
5104 int ufoHasCondDefine (const char *name) {
5105 int res = 0;
5106 if (name != NULL && name[0] != 0) {
5107 const size_t nlen = strlen(name);
5108 if (nlen <= 255) {
5109 const uint32_t hash = joaatHashBufCI(name, nlen);
5110 UForthCondDefine *dd = ufoCondDefines;
5111 while (res == 0 && dd != NULL) {
5112 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
5113 res = ufoStrEquCI(name, dd->name);
5115 dd = dd->next;
5119 return res;
5123 //==========================================================================
5125 // ufoCondDefine
5127 //==========================================================================
5128 void ufoCondDefine (const char *name) {
5129 if (name != NULL && name[0] != 0) {
5130 const size_t nlen = strlen(name);
5131 if (nlen > 255) ufoFatal("conditional define name too long");
5132 const uint32_t hash = joaatHashBufCI(name, nlen);
5133 UForthCondDefine *dd = ufoCondDefines;
5134 int res = 0;
5135 while (res == 0 && dd != NULL) {
5136 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
5137 res = ufoStrEquCI(name, dd->name);
5139 dd = dd->next;
5141 if (res == 0) {
5142 // new define
5143 dd = calloc(1, sizeof(UForthCondDefine));
5144 if (dd == NULL) ufoFatal("out of memory for defines");
5145 dd->name = strdup(name);
5146 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
5147 dd->namelen = (uint32_t)nlen;
5148 dd->hash = hash;
5149 dd->next = ufoCondDefines;
5150 ufoCondDefines = dd;
5156 //==========================================================================
5158 // ufoCondUndef
5160 //==========================================================================
5161 void ufoCondUndef (const char *name) {
5162 if (name != NULL && name[0] != 0) {
5163 const size_t nlen = strlen(name);
5164 if (nlen <= 255) {
5165 const uint32_t hash = joaatHashBufCI(name, nlen);
5166 UForthCondDefine *dd = ufoCondDefines;
5167 UForthCondDefine *prev = NULL;
5168 while (dd != NULL) {
5169 if (dd->hash == hash && dd->namelen == (uint32_t)nlen) {
5170 if (ufoStrEquCI(name, dd->name)) {
5171 if (prev != NULL) prev->next = dd->next; else ufoCondDefines = dd->next;
5172 free(dd->name);
5173 free(dd);
5174 dd = NULL;
5177 if (dd != NULL) { prev = dd; dd = dd->next; }
5184 // ($DEFINE)
5185 // ( addr count -- )
5186 UFWORD(PAR_DLR_DEFINE) {
5187 uint32_t count = ufoPop();
5188 uint32_t addr = ufoPop();
5189 if (count == 0) ufoFatal("empty define");
5190 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
5191 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
5192 UForthCondDefine *dd;
5193 for (dd = ufoCondDefines; dd != NULL; dd = dd->next) {
5194 if (dd->hash == hash && dd->namelen == count) {
5195 if (ufoBufEquCI(addr, count, dd->name)) return;
5198 // new define
5199 dd = calloc(1, sizeof(UForthCondDefine));
5200 if (dd == NULL) ufoFatal("out of memory for defines");
5201 dd->name = calloc(1, count + 1u);
5202 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
5203 for (uint32_t f = 0; f < count; f += 1) {
5204 ((unsigned char *)dd->name)[f] = ufoImgGetU8Ext(addr + f);
5206 dd->namelen = count;
5207 dd->hash = hash;
5208 dd->next = ufoCondDefines;
5209 ufoCondDefines = dd;
5212 // ($UNDEF)
5213 // ( addr count -- )
5214 UFWORD(PAR_DLR_UNDEF) {
5215 uint32_t count = ufoPop();
5216 uint32_t addr = ufoPop();
5217 if (count == 0) ufoFatal("empty define");
5218 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
5219 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
5220 UForthCondDefine *prev = NULL;
5221 UForthCondDefine *dd;
5222 for (dd = ufoCondDefines; dd != NULL; prev = dd, dd = dd->next) {
5223 if (dd->hash == hash && dd->namelen == count) {
5224 if (ufoBufEquCI(addr, count, dd->name)) {
5225 if (prev == NULL) ufoCondDefines = dd->next; else prev->next = dd->next;
5226 free(dd->name);
5227 free(dd);
5228 return;
5234 // ($DEFINED?)
5235 // ( addr count -- bool )
5236 UFWORD(PAR_DLR_DEFINEDQ) {
5237 uint32_t count = ufoPop();
5238 uint32_t addr = ufoPop();
5239 if (count == 0) ufoFatal("empty define");
5240 if (count >= UFO_MAX_WORD_LENGTH) ufoFatal("define too long");
5241 const uint32_t hash = ufoHashBuf(addr, count, 0x20);
5242 int found = 0;
5243 UForthCondDefine *dd = ufoCondDefines;
5244 while (!found && dd != NULL) {
5245 if (dd->hash == hash && dd->namelen == count) {
5246 found = ufoBufEquCI(addr, count, dd->name);
5248 dd = dd->next;
5250 ufoPushBool(found);
5254 // ////////////////////////////////////////////////////////////////////////// //
5255 // error reporting
5258 // ERROR
5259 // ( addr count -- )
5260 UFWORD(ERROR) {
5261 uint32_t count = ufoPop();
5262 uint32_t addr = ufoPop();
5263 if (count & (1u<<31)) ufoFatal("invalid error message");
5264 if (count == 0) ufoFatal("some error");
5265 if (count > (uint32_t)sizeof(ufoErrMsgBuf) - 1u) count = (uint32_t)sizeof(ufoErrMsgBuf) - 1u;
5266 for (uint32_t f = 0; f < count; f += 1) {
5267 ufoErrMsgBuf[f] = (char)ufoImgGetU8Ext(addr + f);
5269 ufoErrMsgBuf[count] = 0;
5270 ufoFatal("%s", ufoErrMsgBuf);
5273 // ////////////////////////////////////////////////////////////////////////// //
5274 // includes
5277 static char ufoFNameBuf[4096];
5280 //==========================================================================
5282 // ufoScanIncludeFileName
5284 // `*psys` and `*psoft` must be initialised!
5286 //==========================================================================
5287 static void ufoScanIncludeFileName (uint32_t addr, uint32_t count, char *dest, size_t destsz,
5288 uint32_t *psys, uint32_t *psoft)
5290 uint8_t ch;
5291 uint32_t dpos;
5292 ufo_assert(dest != NULL);
5293 ufo_assert(destsz > 0);
5295 while (count != 0) {
5296 ch = ufoImgGetU8Ext(addr);
5297 if (ch == '!') {
5298 //if (system) ufoFatal("invalid file name (duplicate system mark)");
5299 *psys = 1;
5300 } else if (ch == '?') {
5301 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
5302 *psoft = 1;
5303 } else {
5304 break;
5306 do {
5307 addr += 1; count -= 1;
5308 ch = ufoImgGetU8Ext(addr);
5309 } while (ch <= 32 && count != 0);
5312 if (count == 0) ufoFatal("empty include file name");
5313 if (count >= destsz) ufoFatal("include file name too long");
5315 dpos = 0;
5316 while (count != 0) {
5317 dest[dpos] = (char)ufoImgGetU8Ext(addr); dpos += 1;
5318 addr += 1; count -= 1;
5320 dest[dpos] = 0;
5324 // (INCLUDE-LINE-FOFS)
5325 // ( -- fofs )
5326 UFWORD(PAR_INCLUDE_LINE_FOFS) {
5327 ufoPush((uint32_t)(int32_t)ufoCurrIncludeLineFileOfs);
5330 // (INCLUDE-LINE-SEEK)
5331 // ( lidx fofs -- )
5332 UFWORD(PAR_INCLUDE_LINE_SEEK) {
5333 uint32_t fofs = ufoPop();
5334 uint32_t lidx = ufoPop();
5335 if (lidx >= 0x0fffffffU) lidx = 0;
5336 if (ufoInFile == NULL) ufoFatal("cannot seek without opened include file");
5337 if (fseek(ufoInFile, (long)fofs, SEEK_SET) != 0) {
5338 ufoFatal("error seeking in include file");
5340 ufoInFileLine = lidx;
5343 // (INCLUDE-DEPTH)
5344 // ( -- depth )
5345 // return number of items in include stack
5346 UFWORD(PAR_INCLUDE_DEPTH) {
5347 ufoPush(ufoFileStackPos);
5350 // (INCLUDE-FILE-ID)
5351 // ( isp -- id ) -- isp 0 is current, then 1, etc.
5352 // each include file has unique non-zero id.
5353 UFWORD(PAR_INCLUDE_FILE_ID) {
5354 const uint32_t isp = ufoPop();
5355 if (isp == 0) {
5356 ufoPush(ufoFileId);
5357 } else if (isp <= ufoFileStackPos) {
5358 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
5359 ufoPush(stk->id);
5360 } else {
5361 ufoFatal("invalid include stack index");
5365 // (INCLUDE-FILE-LINE)
5366 // ( isp -- line )
5367 UFWORD(PAR_INCLUDE_FILE_LINE) {
5368 const uint32_t isp = ufoPop();
5369 if (isp == 0) {
5370 ufoPush(ufoInFileLine);
5371 } else if (isp <= ufoFileStackPos) {
5372 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
5373 ufoPush(stk->fline);
5374 } else {
5375 ufoFatal("invalid include stack index");
5379 // (INCLUDE-FILE-NAME)
5380 // ( isp -- addr count )
5381 // current file name; at PAD
5382 UFWORD(PAR_INCLUDE_FILE_NAME) {
5383 const uint32_t isp = ufoPop();
5384 const char *fname = NULL;
5385 if (isp == 0) {
5386 fname = ufoInFileName;
5387 } else if (isp <= ufoFileStackPos) {
5388 UFOFileStackEntry *stk = &ufoFileStack[ufoFileStackPos - isp];
5389 fname = stk->fname;
5390 } else {
5391 ufoFatal("invalid include stack index");
5393 UFCALL(PAD);
5394 uint32_t addr = ufoPop();
5395 uint32_t count = 0;
5396 if (fname != NULL) {
5397 while (fname[count] != 0) {
5398 ufoImgPutU8Ext(addr + count, ((const unsigned char *)fname)[count]);
5399 count += 1;
5402 ufoImgPutU8Ext(addr + count, 0);
5403 ufoPush(addr);
5404 ufoPush(count);
5408 // (INCLUDE-BUILD-NAME)
5409 // ( addr count soft? system? -- addr count )
5410 // to PAD
5411 UFWORD(PAR_INCLUDE_BUILD_NAME) {
5412 uint32_t system = ufoPop();
5413 uint32_t softinclude = ufoPop();
5414 uint32_t count = ufoPop();
5415 uint32_t addr = ufoPop();
5417 if ((count & ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5419 ufoScanIncludeFileName(addr, count, ufoFNameBuf, sizeof(ufoFNameBuf),
5420 &system, &softinclude);
5422 char *ffn = ufoCreateIncludeName(ufoFNameBuf, system, (system ? ufoLastSysIncPath : ufoLastIncPath));
5423 addr = UFO_PAD_ADDR + 4u;
5424 count = 0;
5425 while (ffn[count] != 0) {
5426 ufoImgPutU8Ext(addr + count, ((const unsigned char *)ffn)[count]);
5427 count += 1u;
5429 free(ffn);
5430 ufoImgPutU8Ext(addr + count, 0);
5431 ufoImgPutU32(addr - 4u, count);
5432 ufoPush(addr);
5433 ufoPush(count);
5436 // (INCLUDE-NO-REFILL)
5437 // ( addr count soft? system? -- )
5438 UFWORD(PAR_INCLUDE_NO_REFILL) {
5439 uint32_t system = ufoPop();
5440 uint32_t softinclude = ufoPop();
5441 uint32_t count = ufoPop();
5442 uint32_t addr = ufoPop();
5444 if (ufoMode == UFO_MODE_MACRO) ufoFatal("macros cannot include files");
5446 if ((count & ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
5448 ufoScanIncludeFileName(addr, count, ufoFNameBuf, sizeof(ufoFNameBuf),
5449 &system, &softinclude);
5451 char *ffn = ufoCreateIncludeName(ufoFNameBuf, system, (system ? ufoLastSysIncPath : ufoLastIncPath));
5452 #ifdef WIN32
5453 FILE *fl = fopen(ffn, "rb");
5454 #else
5455 FILE *fl = fopen(ffn, "r");
5456 #endif
5457 if (!fl) {
5458 if (softinclude) { free(ffn); return; }
5459 ufoFatal("include file '%s' not found", ffn);
5461 #ifdef UFO_DEBUG_INCLUDE
5462 fprintf(stderr, "INC-PUSH: new fname: %s\n", ffn);
5463 #endif
5464 ufoPushInFile();
5465 ufoInFile = fl;
5466 ufoInFileLine = 0;
5467 ufoSetInFileNameReuse(ffn);
5468 ufoFileId = ufoLastUsedFileId;
5469 setLastIncPath(ufoInFileName, system);
5472 // (INCLUDE-DROP)
5473 // ( -- )
5474 UFWORD(PAR_INCLUDE_DROP) {
5475 ufoPopInFile();
5478 // (INCLUDE)
5479 // ( addr count soft? system? -- )
5480 UFWORD(PAR_INCLUDE) {
5481 UFCALL(PAR_INCLUDE_NO_REFILL);
5482 // trigger next line loading
5483 UFCALL(REFILL);
5484 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
5487 // $INCLUDE "str"
5488 UFWORD(DLR_INCLUDE_IMM) {
5489 int soft = 0, system = 0;
5490 // parse include filename
5491 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5492 uint8_t ch = ufoTibPeekCh();
5493 if (ch == '"') {
5494 ufoTibSkipCh(); // skip quote
5495 ufoPush(34);
5496 } else if (ch == '<') {
5497 ufoTibSkipCh(); // skip quote
5498 ufoPush(62);
5499 system = 1;
5500 } else {
5501 ufoFatal("expected quoted string");
5503 UFCALL(PARSE);
5504 if (!ufoPop()) ufoFatal("file name expected");
5505 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5506 if (ufoTibPeekCh() != 0) {
5507 ufoFatal("$INCLUDE doesn't accept extra args yet");
5509 // ( addr count soft? system? -- )
5510 ufoPushBool(soft); ufoPushBool(system); UFCALL(PAR_INCLUDE);
5514 //==========================================================================
5516 // ufoCreateFileGuard
5518 //==========================================================================
5519 static const char *ufoCreateFileGuard (const char *fname) {
5520 if (fname == NULL || fname[0] == 0) return NULL;
5521 char *rp = ufoRealPath(fname);
5522 if (rp == NULL) return NULL;
5523 #ifdef WIN32
5524 for (char *s = rp; *s; s += 1) if (*s == '\\') *s = '/';
5525 #endif
5526 // hash the buffer; extract file name; create string with path len, file name, and hash
5527 const size_t orgplen = strlen(rp);
5528 const uint32_t phash = joaatHashBuf(rp, orgplen, 0);
5529 size_t plen = orgplen;
5530 while (plen != 0 && rp[plen - 1u] != '/') plen -= 1;
5531 snprintf(ufoRealPathHashBuf, sizeof(ufoRealPathHashBuf),
5532 "__INCLUDE_GUARD_%08X_%08X_%s__", phash, (uint32_t)orgplen, rp + plen);
5533 return ufoRealPathHashBuf;
5537 // $INCLUDE-ONCE "str"
5538 // includes file only once; unreliable on shitdoze, i believe
5539 UFWORD(DLR_INCLUDE_ONCE_IMM) {
5540 uint32_t softinclude = 0, system = 0;
5541 // parse include filename
5542 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5543 uint8_t ch = ufoTibPeekCh();
5544 if (ch == '"') {
5545 ufoTibSkipCh(); // skip quote
5546 ufoPush(34);
5547 } else if (ch == '<') {
5548 ufoTibSkipCh(); // skip quote
5549 ufoPush(62);
5550 system = 1;
5551 } else {
5552 ufoFatal("expected quoted string");
5554 UFCALL(PARSE);
5555 if (!ufoPop()) ufoFatal("file name expected");
5556 const uint32_t count = ufoPop();
5557 const uint32_t addr = ufoPop();
5558 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
5559 if (ufoTibPeekCh() != 0) {
5560 ufoFatal("$REQUIRE doesn't accept extra args yet");
5562 ufoScanIncludeFileName(addr, count, ufoRealPathHashBuf, sizeof(ufoRealPathHashBuf),
5563 &system, &softinclude);
5564 char *incfname = ufoCreateIncludeName(ufoRealPathHashBuf, system, (system ? ufoLastSysIncPath : ufoLastIncPath));
5565 if (incfname == NULL) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf);
5566 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5567 // this will overwrite `ufoRealPathHashBuf`
5568 const char *guard = ufoCreateFileGuard(incfname);
5569 free(incfname);
5570 if (guard == NULL) {
5571 if (!softinclude) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf);
5572 return;
5574 #if 0
5575 fprintf(stderr, "GUARD: <%s>\n", guard);
5576 #endif
5577 // now check for the guard
5578 const uint32_t glen = (uint32_t)strlen(guard);
5579 const uint32_t ghash = joaatHashBuf(guard, glen, 0);
5580 UForthCondDefine *dd;
5581 for (dd = ufoCondDefines; dd != NULL; dd = dd->next) {
5582 if (dd->hash == ghash && dd->namelen == glen && strcmp(guard, dd->name) == 0) {
5583 // nothing to do: already included
5584 return;
5587 // add guard
5588 dd = calloc(1, sizeof(UForthCondDefine));
5589 if (dd == NULL) ufoFatal("out of memory for defines");
5590 dd->name = calloc(1, glen + 1u);
5591 if (dd->name == NULL) { free(dd); ufoFatal("out of memory for defines"); }
5592 strcpy(dd->name, guard);
5593 dd->namelen = glen;
5594 dd->hash = ghash;
5595 dd->next = ufoCondDefines;
5596 ufoCondDefines = dd;
5597 // ( addr count soft? system? -- )
5598 ufoPush(addr); ufoPush(count); ufoPushBool(softinclude); ufoPushBool(system);
5599 UFCALL(PAR_INCLUDE);
5603 // ////////////////////////////////////////////////////////////////////////// //
5604 // handles
5607 // HANDLE:NEW
5608 // ( typeid -- hx )
5609 UFWORD(PAR_NEW_HANDLE) {
5610 const uint32_t typeid = ufoPop();
5611 if (typeid == UFO_HANDLE_FREE) ufoFatal("invalid handle typeid");
5612 UfoHandle *hh = ufoAllocHandle(typeid);
5613 ufoPush(hh->ufoHandle);
5616 // HANDLE:FREE
5617 // ( hx -- )
5618 UFWORD(PAR_FREE_HANDLE) {
5619 const uint32_t hx = ufoPop();
5620 if (hx != 0) {
5621 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("trying to free something that is not a handle");
5622 UfoHandle *hh = ufoGetHandle(hx);
5623 if (hh == NULL) ufoFatal("trying to free invalid handle");
5624 ufoFreeHandle(hh);
5628 // HANDLE:TYPEID@
5629 // ( hx -- typeid )
5630 UFWORD(PAR_HANDLE_GET_TYPEID) {
5631 const uint32_t hx = ufoPop();
5632 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5633 UfoHandle *hh = ufoGetHandle(hx);
5634 if (hh == NULL) ufoFatal("invalid handle");
5635 ufoPush(hh->typeid);
5638 // HANDLE:TYPEID!
5639 // ( typeid hx -- )
5640 UFWORD(PAR_HANDLE_SET_TYPEID) {
5641 const uint32_t hx = ufoPop();
5642 const uint32_t typeid = ufoPop();
5643 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5644 if (typeid == UFO_HANDLE_FREE) ufoFatal("invalid handle typeid");
5645 UfoHandle *hh = ufoGetHandle(hx);
5646 if (hh == NULL) ufoFatal("invalid handle");
5647 hh->typeid = typeid;
5650 // HANDLE:SIZE@
5651 // ( hx -- size )
5652 UFWORD(PAR_HANDLE_GET_SIZE) {
5653 const uint32_t hx = ufoPop();
5654 if (hx != 0) {
5655 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5656 UfoHandle *hh = ufoGetHandle(hx);
5657 if (hh == NULL) ufoFatal("invalid handle");
5658 ufoPush(hh->size);
5659 } else {
5660 ufoPush(0);
5664 // HANDLE:SIZE!
5665 // ( size hx -- )
5666 UFWORD(PAR_HANDLE_SET_SIZE) {
5667 const uint32_t hx = ufoPop();
5668 const uint32_t size = ufoPop();
5669 if (size > 0x04000000) ufoFatal("invalid handle size");
5670 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5671 UfoHandle *hh = ufoGetHandle(hx);
5672 if (hh == NULL) ufoFatal("invalid handle");
5673 if (hh->size != size) {
5674 if (size == 0) {
5675 free(hh->data);
5676 hh->data = NULL;
5677 } else {
5678 uint8_t *nx = realloc(hh->data, size * sizeof(hh->data[0]));
5679 if (nx == NULL) ufoFatal("out of memory for handle of size %u", size);
5680 hh->data = nx;
5681 if (size > hh->size) memset(hh->data, 0, size - hh->size);
5683 hh->size = size;
5684 if (hh->used > size) hh->used = size;
5688 // HANDLE:USED@
5689 // ( hx -- used )
5690 UFWORD(PAR_HANDLE_GET_USED) {
5691 const uint32_t hx = ufoPop();
5692 if (hx != 0) {
5693 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5694 UfoHandle *hh = ufoGetHandle(hx);
5695 if (hh == NULL) ufoFatal("invalid handle");
5696 ufoPush(hh->used);
5697 } else {
5698 ufoPush(0);
5702 // HANDLE:USED!
5703 // ( size hx -- )
5704 UFWORD(PAR_HANDLE_SET_USED) {
5705 const uint32_t hx = ufoPop();
5706 const uint32_t used = ufoPop();
5707 if (used > 0x04000000) ufoFatal("invalid handle used");
5708 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle");
5709 UfoHandle *hh = ufoGetHandle(hx);
5710 if (hh == NULL) ufoFatal("invalid handle");
5711 if (used > hh->size) ufoFatal("handle used %u out of range (%u)", used, hh->size);
5712 hh->used = used;
5715 #define POP_PREPARE_HANDLE() \
5716 const uint32_t hx = ufoPop(); \
5717 uint32_t idx = ufoPop(); \
5718 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5719 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5720 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5721 UfoHandle *hh = ufoGetHandle(hx); \
5722 if (hh == NULL) ufoFatal("invalid handle")
5724 // HANDLE:C@
5725 // ( idx hx -- value )
5726 UFWORD(PAR_HANDLE_LOAD_BYTE) {
5727 POP_PREPARE_HANDLE();
5728 if (idx >= hh->size) ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5729 ufoPush(hh->data[idx]);
5732 // HANDLE:W@
5733 // ( idx hx -- value )
5734 UFWORD(PAR_HANDLE_LOAD_WORD) {
5735 POP_PREPARE_HANDLE();
5736 if (idx >= hh->size || hh->size - idx < 2u) {
5737 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5739 #ifdef UFO_FAST_MEM_ACCESS
5740 ufoPush(*(const uint16_t *)(hh->data + idx));
5741 #else
5742 uint32_t res = hh->data[idx];
5743 res |= hh->data[idx + 1u] << 8;
5744 ufoPush(res);
5745 #endif
5748 // HANDLE:@
5749 // ( idx hx -- value )
5750 UFWORD(PAR_HANDLE_LOAD_CELL) {
5751 POP_PREPARE_HANDLE();
5752 if (idx >= hh->size || hh->size - idx < 4u) {
5753 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5755 #ifdef UFO_FAST_MEM_ACCESS
5756 ufoPush(*(const uint32_t *)(hh->data + idx));
5757 #else
5758 uint32_t res = hh->data[idx];
5759 res |= hh->data[idx + 1u] << 8;
5760 res |= hh->data[idx + 2u] << 16;
5761 res |= hh->data[idx + 3u] << 24;
5762 ufoPush(res);
5763 #endif
5766 // HANDLE:C!
5767 // ( value idx hx -- value )
5768 UFWORD(PAR_HANDLE_STORE_BYTE) {
5769 POP_PREPARE_HANDLE();
5770 const uint32_t value = ufoPop();
5771 if (idx >= hh->size) ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5772 hh->data[idx] = value;
5775 // HANDLE:W!
5776 // ( value idx hx -- )
5777 UFWORD(PAR_HANDLE_STORE_WORD) {
5778 POP_PREPARE_HANDLE();
5779 const uint32_t value = ufoPop();
5780 if (idx >= hh->size || hh->size - idx < 2u) {
5781 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5783 #ifdef UFO_FAST_MEM_ACCESS
5784 *(uint16_t *)(hh->data + idx) = (uint16_t)value;
5785 #else
5786 hh->data[idx] = (uint8_t)value;
5787 hh->data[idx + 1u] = (uint8_t)(value >> 8);
5788 #endif
5791 // HANDLE:!
5792 // ( value idx hx -- )
5793 UFWORD(PAR_HANDLE_STORE_CELL) {
5794 POP_PREPARE_HANDLE();
5795 const uint32_t value = ufoPop();
5796 if (idx >= hh->size || hh->size - idx < 4u) {
5797 ufoFatal("handle index %u out of range (%u)", idx, hh->size);
5799 #ifdef UFO_FAST_MEM_ACCESS
5800 *(uint32_t *)(hh->data + idx) = value;
5801 #else
5802 hh->data[idx] = (uint8_t)value;
5803 hh->data[idx + 1u] = (uint8_t)(value >> 8);
5804 hh->data[idx + 2u] = (uint8_t)(value >> 16);
5805 hh->data[idx + 3u] = (uint8_t)(value >> 24);
5806 #endif
5810 // HANDLE:LOAD-FILE
5811 // ( addr count -- stx / FALSE )
5812 UFWORD(PAR_HANDLE_LOAD_FILE) {
5813 uint32_t count = ufoPop();
5814 uint32_t addr = ufoPop();
5816 if ((count & ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5818 uint8_t *dest = (uint8_t *)ufoFNameBuf;
5819 while (count != 0 && dest < (uint8_t *)ufoFNameBuf + sizeof(ufoFNameBuf)) {
5820 uint8_t ch = ufoImgGetU8Ext(addr);
5821 *dest = ch;
5822 dest += 1u; addr += 1u; count -= 1u;
5824 if (dest == (uint8_t *)ufoFNameBuf + sizeof(ufoFNameBuf)) ufoFatal("file name too long");
5825 *dest = 0;
5827 if (*ufoFNameBuf == 0) ufoFatal("empty file name");
5829 char *ffn = ufoCreateIncludeName(ufoFNameBuf, 0/*system*/, ufoLastIncPath);
5830 #ifdef WIN32
5831 FILE *fl = fopen(ffn, "rb");
5832 #else
5833 FILE *fl = fopen(ffn, "r");
5834 #endif
5835 if (!fl) {
5836 free(ffn);
5837 ufoPush(0);
5838 return;
5841 if (fseek(fl, 0, SEEK_END) != 0) {
5842 fclose(fl);
5843 ufoFatal("seek error in file '%s'", ffn);
5846 long sz = ftell(fl);
5847 if (sz < 0 || sz >= 1024 * 1024 * 64) {
5848 fclose(fl);
5849 ufoFatal("tell error in file '%s' (or too big)", ffn);
5852 if (fseek(fl, 0, SEEK_SET) != 0) {
5853 fclose(fl);
5854 ufoFatal("seek error in file '%s'", ffn);
5857 UfoHandle *hh = ufoAllocHandle(0);
5858 if (sz != 0) {
5859 hh->data = malloc((uint32_t)sz);
5860 if (hh->data == NULL) {
5861 fclose(fl);
5862 ufoFatal("out of memory for file '%s'", ffn);
5864 hh->size = (uint32_t)sz;
5865 if (fread(hh->data, (uint32_t)sz, 1, fl) != 1) {
5866 fclose(fl);
5867 ufoFatal("error reading file '%s'", ffn);
5869 fclose(fl);
5872 free(ffn);
5873 ufoPush(hh->ufoHandle);
5877 // ////////////////////////////////////////////////////////////////////////// //
5878 // utils
5881 // DEBUG:(DECOMPILE-CFA)
5882 // ( cfa -- )
5883 UFWORD(DEBUG_DECOMPILE_CFA) {
5884 const uint32_t cfa = ufoPop();
5885 ufoFlushOutput();
5886 ufoDecompileWord(cfa);
5889 // DEBUG:(DECOMPILE-MEM)
5890 // ( addr-start addr-end -- )
5891 UFWORD(DEBUG_DECOMPILE_MEM) {
5892 const uint32_t end = ufoPop();
5893 const uint32_t start = ufoPop();
5894 ufoFlushOutput();
5895 ufoDecompilePart(start, end, 0);
5898 // GET-MSECS
5899 // ( -- u32 )
5900 UFWORD(GET_MSECS) {
5901 ufoPush((uint32_t)ufo_get_msecs());
5904 // this is called by INTERPRET when it is out of input stream
5905 UFWORD(UFO_INTERPRET_FINISHED_ACTION) {
5906 ufoVMStop = 1;
5909 // MTASK:NEW-STATE
5910 // ( cfa -- stid )
5911 UFWORD(MT_NEW_STATE) {
5912 UfoState *st = ufoNewState();
5913 ufoInitStateUserVars(st, ufoPop());
5914 ufoPush(st->id);
5917 // MTASK:FREE-STATE
5918 // ( stid -- )
5919 UFWORD(MT_FREE_STATE) {
5920 UfoState *st = ufoFindState(ufoPop());
5921 if (st == NULL) ufoFatal("cannot free unknown state");
5922 if (st == ufoCurrState) ufoFatal("cannot free current state");
5923 ufoFreeState(st);
5926 // MTASK:STATE-NAME@
5927 // ( stid -- addr count )
5928 // to PAD
5929 UFWORD(MT_GET_STATE_NAME) {
5930 UfoState *st = ufoFindState(ufoPop());
5931 if (st == NULL) ufoFatal("unknown state");
5932 UFCALL(PAD);
5933 uint32_t addr = ufoPop();
5934 uint32_t count = 0;
5935 while (st->name[count] != 0) {
5936 ufoImgPutU8Ext(addr + count, ((const unsigned char *)st->name)[count]);
5937 count += 1u;
5939 ufoImgPutU8Ext(addr + count, 0);
5940 ufoPush(addr);
5941 ufoPush(count);
5944 // MTASK:STATE-NAME!
5945 // ( addr count stid -- )
5946 UFWORD(MT_SET_STATE_NAME) {
5947 UfoState *st = ufoFindState(ufoPop());
5948 if (st == NULL) ufoFatal("unknown state");
5949 uint32_t count = ufoPop();
5950 uint32_t addr = ufoPop();
5951 if ((count & ((uint32_t)1 << 31)) == 0) {
5952 if (count > UFO_MAX_TASK_NAME) ufoFatal("task name too long");
5953 for (uint32_t f = 0; f < count; f += 1u) {
5954 ((unsigned char *)st->name)[f] = ufoImgGetU8Ext(addr + f);
5956 st->name[count] = 0;
5960 // MTASK:STATE-FIRST
5961 // ( -- stid )
5962 UFWORD(MT_STATE_FIRST) {
5963 uint32_t fidx = 0;
5964 while (fidx != (uint32_t)(UFO_MAX_STATES/32) && ufoStateUsedBitmap[fidx] == 0) fidx += 1u;
5965 // there should be at least one allocated state
5966 ufo_assert(fidx != (uint32_t)(UFO_MAX_STATES/32));
5967 uint32_t bmp = ufoStateUsedBitmap[fidx];
5968 fidx *= 32u;
5969 while ((bmp & 0x01) == 0) { fidx += 1u; bmp >>= 1; }
5970 ufoPush(fidx + 1u);
5973 // MTASK:STATE-NEXT
5974 // ( stid -- stid / 0 )
5975 UFWORD(MT_STATE_NEXT) {
5976 uint32_t stid = ufoPop();
5977 if (stid != 0 && stid < (uint32_t)(UFO_MAX_STATES/32)) {
5978 // it is already incremented for us, yay!
5979 uint32_t fidx = stid / 32u;
5980 uint8_t fofs = stid & 0x1f;
5981 while (fidx < (uint32_t)(UFO_MAX_STATES/32)) {
5982 const uint32_t bmp = ufoStateUsedBitmap[fidx];
5983 if (bmp != 0) {
5984 while (fofs != 32u) {
5985 if ((bmp & ((uint32_t)1 << (fofs & 0x1f))) == 0) fofs += 1u;
5987 if (fofs != 32u) {
5988 ufoPush(fidx * 32u + fofs + 1u);
5989 return; // sorry!
5992 fidx += 1u; fofs = 0;
5995 ufoPush(0);
5999 // MTASK:YIELD-TO
6000 // ( ... argc stid -- )
6001 UFWORD(MT_YIELD_TO) {
6002 UfoState *st = ufoFindState(ufoPop());
6003 if (st == NULL) ufoFatal("cannot yield to unknown state");
6004 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
6005 const uint32_t argc = ufoPop();
6006 if (argc > 256) ufoFatal("too many YIELD-TO arguments");
6007 UfoState *curst = ufoCurrState;
6008 if (st != ufoCurrState) {
6009 for (uint32_t f = 0; f < argc; f += 1) {
6010 ufoCurrState = curst;
6011 const uint32_t n = ufoPop();
6012 ufoCurrState = st;
6013 ufoPush(n);
6015 ufoCurrState = curst; // we need to use API call to switch states
6017 ufoSwitchToState(st); // always use API call for this!
6018 ufoPush(argc);
6019 ufoPush(curst->id);
6022 // MTASK:SET-SELF-AS-DEBUGGER
6023 // ( -- )
6024 UFWORD(MT_SET_SELF_AS_DEBUGGER) {
6025 ufoDebuggerState = ufoCurrState;
6028 // DEBUG:(BP)
6029 // ( -- )
6030 // debugger task receives debugge stid on the data stack, and -1 as argc.
6031 // i.e. debugger stask is: ( -1 old-stid )
6032 UFWORD(MT_DEBUGGER_BP) {
6033 if (ufoDebuggerState != NULL && ufoCurrState != ufoDebuggerState && ufoIsGoodTTY()) {
6034 UfoState *st = ufoCurrState;
6035 ufoSwitchToState(ufoDebuggerState); // always use API call for this!
6036 ufoPush(-1);
6037 ufoPush(st->id);
6038 ufoSingleStep = 0;
6039 } else {
6040 UFCALL(UFO_BACKTRACE);
6044 // MTASK:DEBUGGER-RESUME
6045 // ( stid -- )
6046 UFWORD(MT_RESUME_DEBUGEE) {
6047 if (ufoCurrState != ufoDebuggerState) ufoFatal("cannot resume from non-debugger");
6048 UfoState *st = ufoFindState(ufoPop());
6049 if (st == NULL) ufoFatal("cannot yield to unknown state");
6050 if (st == ufoCurrState) ufoFatal("cannot resume into debugger itself");
6051 ufoSwitchToState(st); // always use API call for this!
6052 ufoSingleStep = 0;
6055 // MTASK:DEBUGGER-SINGLE-STEP
6056 // ( stid -- )
6057 UFWORD(MT_SINGLE_STEP_DEBUGEE) {
6058 if (ufoCurrState != ufoDebuggerState) ufoFatal("cannot resume from non-debugger");
6059 UfoState *st = ufoFindState(ufoPop());
6060 if (st == NULL) ufoFatal("cannot yield to unknown state");
6061 if (st == ufoCurrState) ufoFatal("cannot resume into debugger itself");
6062 ufoSwitchToState(st); // always use API call for this!
6063 ufoSingleStep = 2; // it will be decremented after returning from this word
6066 // MTASK:STATE-IP@
6067 // ( stid -- ip )
6068 UFWORD(MT_STATE_IP_GET) {
6069 UfoState *st = ufoFindState(ufoPop());
6070 if (st == NULL) ufoFatal("unknown state");
6071 ufoPush(st->IP);
6074 // MTASK:STATE-IP!
6075 // ( ip stid -- )
6076 UFWORD(MT_STATE_IP_SET) {
6077 UfoState *st = ufoFindState(ufoPop());
6078 if (st == NULL) ufoFatal("unknown state");
6079 st->IP = ufoPop();
6082 // MTASK:STATE-A>
6083 // ( stid -- ip )
6084 UFWORD(MT_STATE_REGA_GET) {
6085 UfoState *st = ufoFindState(ufoPop());
6086 if (st == NULL) ufoFatal("unknown state");
6087 ufoPush(st->regA);
6090 // MTASK:STATE->A
6091 // ( ip stid -- )
6092 UFWORD(MT_STATE_REGA_SET) {
6093 UfoState *st = ufoFindState(ufoPop());
6094 if (st == NULL) ufoFatal("unknown state");
6095 st->regA = ufoPop();
6098 // MTASK:STATE-USER@
6099 // ( addr stid -- value )
6100 UFWORD(MT_STATE_USER_GET) {
6101 UfoState *st = ufoFindState(ufoPop());
6102 if (st == NULL) ufoFatal("unknown state");
6103 const uint32_t addr = ufoPop();
6104 if ((addr & UFO_ADDR_TEMP_BIT) != 0 && (addr & UFO_ADDR_TEMP_MASK) + 3u < st->imageTempSize) {
6105 uint32_t v = *(const uint32_t *)((const uint8_t *)st->imageTemp + (addr & UFO_ADDR_TEMP_MASK));
6106 ufoPush(v);
6107 } else {
6108 ufoFatal("invalid user area address");
6112 // MTASK:STATE-USER!
6113 // ( value addr stid -- )
6114 UFWORD(MT_STATE_USER_SET) {
6115 UfoState *st = ufoFindState(ufoPop());
6116 if (st == NULL) ufoFatal("unknown state");
6117 const uint32_t addr = ufoPop();
6118 const uint32_t value = ufoPop();
6119 if ((addr & UFO_ADDR_TEMP_BIT) != 0 && (addr & UFO_ADDR_TEMP_MASK) + 3u < st->imageTempSize) {
6120 *(uint32_t *)((const uint8_t *)st->imageTemp + (addr & UFO_ADDR_TEMP_MASK)) = value;
6121 } else {
6122 ufoFatal("invalid user area address");
6126 // MTASK:STATE-RPOPCFA@
6127 // ( -- flag )
6128 UFWORD(MT_STATE_RPOPCFA_GET) {
6129 UfoState *st = ufoFindState(ufoPop());
6130 if (st == NULL) ufoFatal("unknown state");
6131 ufoPush(st->vmRPopCFA);
6134 // MTASK:STATE-RPOPCFA!
6135 // ( flag -- )
6136 UFWORD(MT_STATE_RPOPCFA_SET) {
6137 UfoState *st = ufoFindState(ufoPop());
6138 if (st == NULL) ufoFatal("unknown state");
6139 st->vmRPopCFA = ufoPop();
6142 // MTASK:ACTIVE-STATE
6143 // ( -- stid )
6144 UFWORD(MT_ACTIVE_STATE) {
6145 ufoPush(ufoCurrState->id);
6148 // MTASK:YIELDED-FROM
6149 // ( -- stid / 0 )
6150 UFWORD(MT_YIELDED_FROM) {
6151 if (ufoYieldedState != NULL) {
6152 ufoPush(ufoYieldedState->id);
6153 } else {
6154 ufoPush(0);
6158 // MTASK:STATE-SP@
6159 // ( stid -- depth )
6160 UFWORD(MT_DSTACK_DEPTH_GET) {
6161 UfoState *st = ufoFindState(ufoPop());
6162 if (st == NULL) ufoFatal("unknown state");
6163 ufoPush(st->SP);
6166 // MTASK:STATE-RP@
6167 // ( stid -- depth )
6168 UFWORD(MT_RSTACK_DEPTH_GET) {
6169 UfoState *st = ufoFindState(ufoPop());
6170 if (st == NULL) ufoFatal("unknown state");
6171 ufoPush(st->RP - st->RPTop);
6174 // MTASK:STATE-LP@
6175 // ( stid -- lp )
6176 UFWORD(MT_LP_GET) {
6177 UfoState *st = ufoFindState(ufoPop());
6178 if (st == NULL) ufoFatal("unknown state");
6179 ufoPush(st->LP);
6182 // MTASK:STATE-LBP@
6183 // ( stid -- lbp )
6184 UFWORD(MT_LBP_GET) {
6185 UfoState *st = ufoFindState(ufoPop());
6186 if (st == NULL) ufoFatal("unknown state");
6187 ufoPush(st->LBP);
6190 // MTASK:STATE-SP!
6191 // ( depth stid -- )
6192 UFWORD(MT_DSTACK_DEPTH_SET) {
6193 UfoState *st = ufoFindState(ufoPop());
6194 if (st == NULL) ufoFatal("unknown state");
6195 const uint32_t idx = ufoPop();
6196 if (idx >= UFO_DSTACK_SIZE) ufoFatal("invalid stack index %u (%u)", idx, UFO_DSTACK_SIZE);
6197 st->SP = idx;
6200 // MTASK:STATE-RP!
6201 // ( depth stid -- )
6202 UFWORD(MT_RSTACK_DEPTH_SET) {
6203 UfoState *st = ufoFindState(ufoPop());
6204 if (st == NULL) ufoFatal("unknown state");
6205 const uint32_t idx = ufoPop();
6206 const uint32_t left = UFO_RSTACK_SIZE - st->RPTop;
6207 if (idx >= left) ufoFatal("invalid rstack index %u (%u)", idx, left);
6208 st->RP = st->RPTop + idx;
6211 // MTASK:STATE-LP!
6212 // ( lp stid -- )
6213 UFWORD(MT_LP_SET) {
6214 UfoState *st = ufoFindState(ufoPop());
6215 if (st == NULL) ufoFatal("unknown state");
6216 st->LP = ufoPop();
6219 // MTASK:STATE-LBP!
6220 // ( lbp stid -- )
6221 UFWORD(MT_LBP_SET) {
6222 UfoState *st = ufoFindState(ufoPop());
6223 if (st == NULL) ufoFatal("unknown state");
6224 st->LBP = ufoPop();
6227 // MTASK:STATE-DS@
6228 // ( idx stid -- value )
6229 UFWORD(MT_DSTACK_LOAD) {
6230 UfoState *st = ufoFindState(ufoPop());
6231 if (st == NULL) ufoFatal("unknown state");
6232 const uint32_t idx = ufoPop();
6233 if (idx >= st->SP) ufoFatal("invalid stack index %u (%u)", idx, st->SP);
6234 ufoPush(st->dStack[st->SP - idx - 1u]);
6237 // MTASK:STATE-RS@
6238 // ( idx stid -- value )
6239 UFWORD(MT_RSTACK_LOAD) {
6240 UfoState *st = ufoFindState(ufoPop());
6241 if (st == NULL) ufoFatal("unknown state");
6242 const uint32_t idx = ufoPop();
6243 if (idx >= st->RP - st->RPTop) ufoFatal("invalid stack index %u (%u)", idx, st->RP - st->RPTop);
6244 ufoPush(st->dStack[st->RP - idx - 1u]);
6247 // MTASK:STATE-LS@
6248 // ( idx stid -- value )
6249 UFWORD(MT_LSTACK_LOAD) {
6250 UfoState *st = ufoFindState(ufoPop());
6251 if (st == NULL) ufoFatal("unknown state");
6252 const uint32_t idx = ufoPop();
6253 if (idx >= st->LP) ufoFatal("invalid lstack index %u (%u)", idx, st->LP);
6254 ufoPush(st->lStack[st->LP - idx - 1u]);
6257 // MTASK:STATE-DS!
6258 // ( value idx stid -- )
6259 UFWORD(MT_DSTACK_STORE) {
6260 UfoState *st = ufoFindState(ufoPop());
6261 if (st == NULL) ufoFatal("unknown state");
6262 const uint32_t idx = ufoPop();
6263 const uint32_t value = ufoPop();
6264 if (idx >= st->SP) ufoFatal("invalid stack index %u (%u)", idx, st->SP);
6265 st->dStack[st->SP - idx - 1u] = value;
6268 // MTASK:STATE-RS!
6269 // ( value idx stid -- )
6270 UFWORD(MT_RSTACK_STORE) {
6271 UfoState *st = ufoFindState(ufoPop());
6272 if (st == NULL) ufoFatal("unknown state");
6273 const uint32_t idx = ufoPop();
6274 const uint32_t value = ufoPop();
6275 if (idx >= st->RP - st->RPTop) ufoFatal("invalid stack index %u (%u)", idx, st->RP - st->RPTop);
6276 st->dStack[st->RP - idx - 1u] = value;
6279 // MTASK:STATE-LS!
6280 // ( value idx stid -- )
6281 UFWORD(MT_LSTACK_STORE) {
6282 UfoState *st = ufoFindState(ufoPop());
6283 if (st == NULL) ufoFatal("unknown state");
6284 const uint32_t idx = ufoPop();
6285 const uint32_t value = ufoPop();
6286 if (idx >= st->LP) ufoFatal("invalid stack index %u (%u)", idx, st->LP);
6287 st->dStack[st->LP - idx - 1u] = value;
6290 // MTASK:STATE-VSP@
6291 // ( stid -- vsp )
6292 UFWORD(MT_VSP_GET) {
6293 UfoState *st = ufoFindState(ufoPop());
6294 if (st == NULL) ufoFatal("unknown state");
6295 ufoPush(st->VSP);
6298 // MTASK:STATE-VSP!
6299 // ( vsp stid -- )
6300 UFWORD(MT_VSP_SET) {
6301 UfoState *st = ufoFindState(ufoPop());
6302 if (st == NULL) ufoFatal("unknown state");
6303 const uint32_t vsp = ufoPop();
6304 if (vsp > UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
6305 st->VSP = vsp;
6308 // MTASK:STATE-VSP-AT@
6309 // ( idx stidf -- value )
6310 UFWORD(MT_VSP_LOAD) {
6311 UfoState *st = ufoFindState(ufoPop());
6312 if (st == NULL) ufoFatal("unknown state");
6313 const uint32_t vsp = ufoPop();
6314 if (vsp >= UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
6315 ufoPush(st->vocStack[vsp]);
6318 // MTASK:STATE-VSP-AT!
6319 // ( value idx stid -- )
6320 UFWORD(MT_VSP_STORE) {
6321 UfoState *st = ufoFindState(ufoPop());
6322 if (st == NULL) ufoFatal("unknown state");
6323 const uint32_t vsp = ufoPop();
6324 const uint32_t value = ufoPop();
6325 if (vsp > UFO_VOCSTACK_SIZE) ufoFatal("VSP %u out of range (%u)", vsp, UFO_VOCSTACK_SIZE);
6326 st->vocStack[vsp] = value;
6330 #include "urforth_tty.c"
6333 // ////////////////////////////////////////////////////////////////////////// //
6334 // "FILES" words
6337 static unsigned char ufoFileIOBuffer[4096];
6340 //==========================================================================
6342 // ufoPopFileName
6344 //==========================================================================
6345 static char *ufoPopFileName (void) {
6346 uint32_t count = ufoPop();
6347 uint32_t addr = ufoPop();
6349 if ((count & 0x80000000U) != 0) ufoFatal("invalid file name");
6350 if (count == 0) ufoFatal("empty file name");
6351 if (count > (uint32_t)sizeof(ufoFNameBuf) - 1u) ufoFatal("file name too long");
6353 unsigned char *dest = (unsigned char *)ufoFNameBuf;
6354 while (count != 0) {
6355 *dest = ufoImgGetU8Ext(addr);
6356 dest += 1u; addr += 1u; count -= 1u;
6358 *dest = 0;
6360 return ufoFNameBuf;
6363 // FILES:ERRNO
6364 // ( -- errno )
6365 UFWORD(FILES_ERRNO) {
6366 ufoPush((uint32_t)errno);
6369 // FILES:UNLINK
6370 // ( addr count -- success? )
6371 UFWORD(FILES_UNLINK) {
6372 const char *fname = ufoPopFileName();
6373 ufoPushBool(unlink(fname) == 0);
6376 // FILES:OPEN-R/O
6377 // ( addr count -- handle TRUE / FALSE )
6378 UFWORD(FILES_OPEN_RO) {
6379 const char *fname = ufoPopFileName();
6380 const int fd = open(fname, O_RDONLY);
6381 if (fd >= 0) {
6382 ufoPush((uint32_t)fd);
6383 ufoPushBool(1);
6384 } else {
6385 ufoPushBool(0);
6389 // FILES:OPEN-R/W
6390 // ( addr count -- handle TRUE / FALSE )
6391 UFWORD(FILES_OPEN_RW) {
6392 const char *fname = ufoPopFileName();
6393 const int fd = open(fname, O_RDWR);
6394 if (fd >= 0) {
6395 ufoPush((uint32_t)fd);
6396 ufoPushBool(1);
6397 } else {
6398 ufoPushBool(0);
6402 // FILES:CREATE
6403 // ( addr count -- handle TRUE / FALSE )
6404 UFWORD(FILES_CREATE) {
6405 const char *fname = ufoPopFileName();
6406 //FIXME: add variable with default flags
6407 const int fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0644);
6408 if (fd >= 0) {
6409 ufoPush((uint32_t)fd);
6410 ufoPushBool(1);
6411 } else {
6412 ufoPushBool(0);
6416 // FILES:CLOSE
6417 // ( handle -- success? )
6418 UFWORD(FILES_CLOSE) {
6419 const int32_t fd = (int32_t)ufoPop();
6420 if (fd < 0) ufoFatal("invalid file handle in 'CLOSE'");
6421 ufoPushBool(close(fd) == 0);
6424 // FILES:TELL
6425 // ( handle -- ofs TRUE / FALSE )
6426 // `handle` cannot be 0.
6427 UFWORD(FILES_TELL) {
6428 const int32_t fd = (int32_t)ufoPop();
6429 if (fd < 0) ufoFatal("invalid file handle in 'TELL'");
6430 const off_t pos = lseek(fd, 0, SEEK_CUR);
6431 if (pos != (off_t)-1) {
6432 ufoPush((uint32_t)pos);
6433 ufoPushBool(1);
6434 } else {
6435 ufoPushBool(0);
6439 // FILES:SEEK-EX
6440 // ( ofs whence handle -- TRUE / FALSE )
6441 // `handle` cannot be 0.
6442 UFWORD(FILES_SEEK_EX) {
6443 const int32_t fd = (int32_t)ufoPop();
6444 const uint32_t whence = ufoPop();
6445 const uint32_t ofs = ufoPop();
6446 if (fd < 0) ufoFatal("invalid file handle in 'SEEK-EX'");
6447 if (whence != (uint32_t)SEEK_SET &&
6448 whence != (uint32_t)SEEK_CUR &&
6449 whence != (uint32_t)SEEK_END) ufoFatal("invalid `whence` in 'SEEK-EX'");
6450 const off_t pos = lseek(fd, (off_t)ofs, (int)whence);
6451 ufoPushBool(pos != (off_t)-1);
6454 // FILES:SIZE
6455 // ( handle -- size TRUE / FALSE )
6456 // `handle` cannot be 0.
6457 UFWORD(FILES_SIZE) {
6458 const int32_t fd = (int32_t)ufoPop();
6459 if (fd < 0) ufoFatal("invalid file handle in 'SIZE'");
6460 const off_t origpos = lseek(fd, 0, SEEK_CUR);
6461 if (origpos == (off_t)-1) {
6462 ufoPushBool(0);
6463 } else {
6464 const off_t size = lseek(fd, 0, SEEK_END);
6465 if (size == (off_t)-1) {
6466 (void)lseek(origpos, 0, SEEK_SET);
6467 ufoPushBool(0);
6468 } else if (lseek(origpos, 0, SEEK_SET) == origpos) {
6469 ufoPush((uint32_t)size);
6470 ufoPushBool(1);
6471 } else {
6472 ufoPushBool(0);
6477 // FILES:READ
6478 // ( addr count handle -- rdsize TRUE / FALSE )
6479 // `handle` cannot be 0.
6480 UFWORD(FILES_READ) {
6481 const int32_t fd = (int32_t)ufoPop();
6482 if (fd < 0) ufoFatal("invalid file handle in 'READ'");
6483 uint32_t count = ufoPop();
6484 uint32_t addr = ufoPop();
6485 uint32_t done = 0;
6486 if (count != 0) {
6487 if ((count & 0x80000000U) != 0) ufoFatal("invalid number of bytes to read from file");
6488 while (count != done) {
6489 uint32_t rd = (uint32_t)sizeof(ufoFileIOBuffer);
6490 if (rd > count) rd = count;
6491 for (;;) {
6492 const ssize_t xres = read(fd, ufoFileIOBuffer, rd);
6493 if (xres >= 0) { rd = (uint32_t)xres; break; }
6494 if (errno == EINTR) continue;
6495 if (errno == EAGAIN || errno == EWOULDBLOCK) { rd = 0; break; }
6496 // error
6497 ufoPushBool(0);
6498 return;
6500 if (rd == 0) break;
6501 done += rd;
6502 for (uint32_t f = 0; f != rd; f += 1u) {
6503 ufoImgPutU8Ext(addr, ufoFileIOBuffer[f]);
6504 addr += 1u;
6508 ufoPush(done);
6509 ufoPushBool(1);
6512 // FILES:READ-EXACT
6513 // ( addr count handle -- TRUE / FALSE )
6514 // `handle` cannot be 0.
6515 UFWORD(FILES_READ_EXACT) {
6516 const int32_t fd = (int32_t)ufoPop();
6517 if (fd < 0) ufoFatal("invalid file handle in 'READ-EXACT'");
6518 uint32_t count = ufoPop();
6519 uint32_t addr = ufoPop();
6520 if (count != 0) {
6521 if ((count & 0x80000000U) != 0) ufoFatal("invalid number of bytes to read from file");
6522 while (count != 0) {
6523 uint32_t rd = (uint32_t)sizeof(ufoFileIOBuffer);
6524 if (rd > count) rd = count;
6525 for (;;) {
6526 const ssize_t xres = read(fd, ufoFileIOBuffer, rd);
6527 if (xres >= 0) { rd = (uint32_t)xres; break; }
6528 if (errno == EINTR) continue;
6529 if (errno == EAGAIN || errno == EWOULDBLOCK) { rd = 0; break; }
6530 // error
6531 ufoPushBool(0);
6532 return;
6534 if (rd == 0) { ufoPushBool(0); return; } // still error
6535 count -= rd;
6536 for (uint32_t f = 0; f != rd; f += 1u) {
6537 ufoImgPutU8Ext(addr, ufoFileIOBuffer[f]);
6538 addr += 1u;
6542 ufoPushBool(1);
6545 // FILES:WRITE
6546 // ( addr count handle -- TRUE / FALSE )
6547 // `handle` cannot be 0.
6548 UFWORD(FILES_WRITE) {
6549 const int32_t fd = (int32_t)ufoPop();
6550 if (fd < 0) ufoFatal("invalid file handle in 'WRITE'");
6551 uint32_t count = ufoPop();
6552 uint32_t addr = ufoPop();
6553 if (count != 0) {
6554 if ((count & 0x80000000U) != 0) ufoFatal("invalid number of bytes to write to file");
6555 while (count != 0) {
6556 uint32_t wr = (uint32_t)sizeof(ufoFileIOBuffer);
6557 if (wr > count) wr = count;
6558 for (uint32_t f = 0; f != wr; f += 1u) {
6559 ufoFileIOBuffer[f] = ufoImgGetU8Ext(addr + f);
6561 for (;;) {
6562 const ssize_t xres = write(fd, ufoFileIOBuffer, wr);
6563 if (xres >= 0) { wr = (uint32_t)xres; break; }
6564 if (errno == EINTR) continue;
6565 fprintf(stderr, "ERRNO: %d (fd=%d)\n", errno, fd);
6566 //if (errno == EAGAIN || errno == EWOULDBLOCK) { wr = 0; break; }
6567 // error
6568 ufoPushBool(0);
6569 return;
6571 if (wr == 0) { ufoPushBool(1); return; } // still error
6572 count -= wr; addr += wr;
6575 ufoPushBool(1);
6579 // ////////////////////////////////////////////////////////////////////////// //
6580 // states
6583 //==========================================================================
6585 // ufoNewState
6587 // create a new state, its execution will start from the given CFA.
6588 // state is not automatically activated.
6590 //==========================================================================
6591 static UfoState *ufoNewState (void) {
6592 // find free state id
6593 uint32_t fidx = 0;
6594 uint32_t bmp = ufoStateUsedBitmap[0];
6595 while (fidx != (uint32_t)(UFO_MAX_STATES/32) && bmp == ~(uint32_t)0) {
6596 fidx += 1u;
6597 bmp = ufoStateUsedBitmap[fidx];
6599 if (fidx == (uint32_t)(UFO_MAX_STATES/32)) ufoFatal("too many execution states");
6600 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6601 fidx *= 32u;
6602 while ((bmp & 0x01) != 0) { fidx += 1u; bmp >>= 1; }
6603 ufo_assert(fidx < UFO_MAX_STATES);
6604 ufo_assert((ufoStateUsedBitmap[fidx / 32u] & ((uint32_t)1 << (fidx & 0x1f))) == 0);
6605 ufo_assert(ufoStateMap[fidx] == NULL);
6606 UfoState *st = calloc(1, sizeof(UfoState));
6607 if (st == NULL) ufoFatal("out of memory for states");
6608 st->id = fidx + 1u;
6609 ufoStateMap[fidx] = st;
6610 ufoStateUsedBitmap[fidx / 32u] |= ((uint32_t)1 << (fidx & 0x1f));
6611 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6612 return st;
6616 //==========================================================================
6618 // ufoFreeState
6620 // free all memory used for the state, remove it from state list.
6621 // WARNING! never free current state!
6623 //==========================================================================
6624 static void ufoFreeState (UfoState *st) {
6625 if (st != NULL) {
6626 if (st == ufoCurrState) ufoFatal("cannot free active state");
6627 if (ufoYieldedState == st) ufoYieldedState = NULL;
6628 if (ufoDebuggerState == st) ufoDebuggerState = NULL;
6629 const uint32_t fidx = st->id - 1u;
6630 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6631 ufo_assert(fidx < UFO_MAX_STATES);
6632 ufo_assert((ufoStateUsedBitmap[fidx / 32u] & (1u << (fidx & 0x1f))) != 0);
6633 ufo_assert(ufoStateMap[fidx] == st);
6634 // free default TIB handle
6635 UfoState *oldst = ufoCurrState;
6636 ufoCurrState = st;
6637 const uint32_t tib = ufoImgGetU32(ufoAddrDefTIB);
6638 if ((tib & UFO_ADDR_TEMP_BIT) != 0) {
6639 UfoHandle *tibh = ufoGetHandle(tib);
6640 if (tibh != NULL) ufoFreeHandle(tibh);
6642 ufoCurrState = oldst;
6643 // free temp buffer
6644 if (st->imageTemp != NULL) free(st->imageTemp);
6645 free(st);
6646 ufoStateMap[fidx] = NULL;
6647 ufoStateUsedBitmap[fidx / 32u] &= ~((uint32_t)1 << (fidx & 0x1f));
6652 //==========================================================================
6654 // ufoFindState
6656 //==========================================================================
6657 static UfoState *ufoFindState (uint32_t stid) {
6658 UfoState *res = NULL;
6659 if (stid >= 0 && stid <= UFO_MAX_STATES) {
6660 if (stid == 0) {
6661 // current
6662 ufo_assert(ufoCurrState != NULL);
6663 stid = ufoCurrState->id - 1u;
6664 } else {
6665 stid -= 1u;
6667 res = ufoStateMap[stid];
6668 if (res != NULL) {
6669 ufo_assert((ufoStateUsedBitmap[stid / 32u] & (1u << (stid & 0x1f))) != 0);
6670 ufo_assert(res->id == stid + 1u);
6671 } else {
6672 ufo_assert((ufoStateUsedBitmap[stid / 32u] & (1u << (stid & 0x1f))) == 0);
6675 return res;
6679 //==========================================================================
6681 // ufoSwitchToState
6683 //==========================================================================
6684 static void ufoSwitchToState (UfoState *newst) {
6685 ufo_assert(newst != NULL);
6686 if (newst != ufoCurrState) {
6687 ufoCurrState = newst;
6692 // ////////////////////////////////////////////////////////////////////////// //
6693 // initial dictionary definitions
6696 #undef UFWORD
6698 #define UFWORD(name_) do { \
6699 const uint32_t xcfa_ = ufoCFAsUsed; \
6700 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6701 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6702 ufoCFAsUsed += 1; \
6703 ufoDefineNative(""#name_, xcfa_, 0); \
6704 } while (0)
6706 #define UFWORDX(strname_,name_) do { \
6707 const uint32_t xcfa_ = ufoCFAsUsed; \
6708 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6709 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6710 ufoCFAsUsed += 1; \
6711 ufoDefineNative(strname_, xcfa_, 0); \
6712 } while (0)
6714 #define UFWORD_IMM(name_) do { \
6715 const uint32_t xcfa_ = ufoCFAsUsed; \
6716 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6717 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6718 ufoCFAsUsed += 1; \
6719 ufoDefineNative(""#name_, xcfa_, 1); \
6720 } while (0)
6722 #define UFWORDX_IMM(strname_,name_) do { \
6723 const uint32_t xcfa_ = ufoCFAsUsed; \
6724 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
6725 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
6726 ufoCFAsUsed += 1; \
6727 ufoDefineNative(strname_, xcfa_, 1); \
6728 } while (0)
6730 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
6733 //==========================================================================
6735 // ufoFindWordChecked
6737 //==========================================================================
6738 UFO_DISABLE_INLINE uint32_t ufoFindWordChecked (const char *wname) {
6739 const uint32_t cfa = ufoFindWord(wname);
6740 if (cfa == 0) ufoFatal("word '%s' not found", wname);
6741 return cfa;
6745 //==========================================================================
6747 // ufoGetForthVocId
6749 // get "FORTH" vocid
6751 //==========================================================================
6752 uint32_t ufoGetForthVocId (void) {
6753 return ufoForthVocId;
6757 //==========================================================================
6759 // ufoVocSetOnlyDefs
6761 //==========================================================================
6762 void ufoVocSetOnlyDefs (uint32_t vocid) {
6763 ufoImgPutU32(ufoAddrCurrent, vocid);
6764 ufoImgPutU32(ufoAddrContext, vocid);
6768 //==========================================================================
6770 // ufoCreateVoc
6772 // return voc PFA (vocid)
6774 //==========================================================================
6775 uint32_t ufoCreateVoc (const char *wname, uint32_t parentvocid, uint32_t flags) {
6776 // create wordlist struct
6777 // typeid, used by Forth code (structs and such)
6778 ufoImgEmitU32(0); // typeid
6779 // vocid points here, to "LATEST-LFA"
6780 const uint32_t vocid = UFO_GET_DP();
6781 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
6782 ufoImgEmitU32(0); // latest
6783 const uint32_t vlink = UFO_GET_DP();
6784 if ((vocid & UFO_ADDR_TEMP_BIT) == 0) {
6785 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink)); // voclink
6786 ufoImgPutU32(ufoAddrVocLink, vlink); // update voclink
6787 } else {
6788 abort();
6789 ufoImgEmitU32(0);
6791 ufoImgEmitU32(parentvocid); // parent
6792 const uint32_t hdraddr = UFO_GET_DP();
6793 ufoImgEmitU32(0); // word header
6794 // create empty hash table
6795 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) ufoImgEmitU32(0);
6796 // update CONTEXT and CURRENT if this is the first wordlist ever
6797 if (ufoImgGetU32(ufoAddrContext) == 0) {
6798 ufoImgPutU32(ufoAddrContext, vocid);
6800 if (ufoImgGetU32(ufoAddrCurrent) == 0) {
6801 ufoImgPutU32(ufoAddrCurrent, vocid);
6803 // create word header
6804 if (wname != NULL && wname[0] != 0) {
6806 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6807 flags &=
6808 //UFW_FLAG_IMMEDIATE|
6809 //UFW_FLAG_SMUDGE|
6810 //UFW_FLAG_NORETURN|
6811 UFW_FLAG_HIDDEN|
6812 //UFW_FLAG_CBLOCK|
6813 //UFW_FLAG_VOCAB|
6814 //UFW_FLAG_SCOLON|
6815 UFW_FLAG_PROTECTED;
6816 flags |= UFW_FLAG_VOCAB;
6818 flags &= 0xffffff00u;
6819 flags |= UFW_FLAG_VOCAB;
6820 ufoCreateWordHeader(wname, flags);
6821 const uint32_t cfa = UFO_GET_DP();
6822 ufoImgEmitU32(ufoDoVocCFA); // cfa
6823 ufoImgEmitU32(vocid); // pfa
6824 // update vocab header pointer
6825 const uint32_t lfa = UFO_CFA_TO_LFA(cfa);
6826 ufoImgPutU32(hdraddr, UFO_LFA_TO_NFA(lfa));
6827 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6828 ufoDumpWordHeader(lfa);
6829 #endif
6831 return vocid;
6835 //==========================================================================
6837 // ufoSetLatestArgs
6839 //==========================================================================
6840 static void ufoSetLatestArgs (uint32_t warg) {
6841 const uint32_t curr = ufoImgGetU32(ufoAddrCurrent);
6842 const uint32_t lfa = ufoImgGetU32(curr);
6843 const uint32_t nfa = UFO_LFA_TO_NFA(lfa);
6844 uint32_t flags = ufoImgGetU32(nfa);
6845 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
6846 flags &= ~UFW_WARG_MASK;
6847 flags |= warg & UFW_WARG_MASK;
6848 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
6849 ufoImgPutU32(nfa, flags);
6850 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
6851 ufoDumpWordHeader(lfa);
6852 #endif
6856 //==========================================================================
6858 // ufoDefine
6860 //==========================================================================
6861 static void ufoDefineNative (const char *wname, uint32_t cfaidx, int immed) {
6862 cfaidx |= UFO_ADDR_CFA_BIT;
6863 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6864 flags &=
6865 //UFW_FLAG_IMMEDIATE|
6866 //UFW_FLAG_SMUDGE|
6867 //UFW_FLAG_NORETURN|
6868 UFW_FLAG_HIDDEN|
6869 //UFW_FLAG_CBLOCK|
6870 //UFW_FLAG_VOCAB|
6871 //UFW_FLAG_SCOLON|
6872 UFW_FLAG_PROTECTED;
6873 if (immed) flags |= UFW_FLAG_IMMEDIATE;
6874 ufoCreateWordHeader(wname, flags);
6875 ufoImgEmitU32(cfaidx);
6879 //==========================================================================
6881 // ufoDefineConstant
6883 //==========================================================================
6884 static void ufoDefineConstant (const char *name, uint32_t value) {
6885 ufoDefineNative(name, ufoDoConstCFA, 0);
6886 ufoImgEmitU32(value);
6890 //==========================================================================
6892 // ufoDefineUserVar
6894 //==========================================================================
6895 static void ufoDefineUserVar (const char *name, uint32_t addr) {
6896 ufoDefineNative(name, ufoDoUserVariableCFA, 0);
6897 ufoImgEmitU32(addr);
6901 //==========================================================================
6903 // ufoDefineVar
6905 //==========================================================================
6907 static void ufoDefineVar (const char *name, uint32_t value) {
6908 ufoDefineNative(name, ufoDoVarCFA, 0);
6909 ufoImgEmitU32(value);
6914 //==========================================================================
6916 // ufoDefineDefer
6918 //==========================================================================
6920 static void ufoDefineDefer (const char *name, uint32_t value) {
6921 ufoDefineNative(name, ufoDoDeferCFA, 0);
6922 ufoImgEmitU32(value);
6927 //==========================================================================
6929 // ufoHiddenWords
6931 //==========================================================================
6932 static void ufoHiddenWords (void) {
6933 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6934 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6938 //==========================================================================
6940 // ufoPublicWords
6942 //==========================================================================
6943 static void ufoPublicWords (void) {
6944 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6945 ufoImgPutU32(ufoAddrNewWordFlags, flags & ~UFW_FLAG_HIDDEN);
6949 //==========================================================================
6951 // ufoDefineForth
6953 //==========================================================================
6955 static void ufoDefineForth (const char *name) {
6956 ufoDefineNative(name, ufoDoForthCFA, 0);
6961 //==========================================================================
6963 // ufoDefineForthImm
6965 //==========================================================================
6967 static void ufoDefineForthImm (const char *name) {
6968 ufoDefineNative(name, ufoDoForthCFA, 1);
6973 //==========================================================================
6975 // ufoDefineForthHidden
6977 //==========================================================================
6979 static void ufoDefineForthHidden (const char *name) {
6980 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
6981 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
6982 ufoDefineNative(name, ufoDoForthCFA, 0);
6983 ufoImgPutU32(ufoAddrNewWordFlags, flags);
6988 //==========================================================================
6990 // ufoDefineSColonForth
6992 // create word suitable for scattered colon extension
6994 //==========================================================================
6995 static void ufoDefineSColonForth (const char *name) {
6996 ufoDefineNative(name, ufoDoForthCFA, 0);
6997 // placeholder for scattered colon
6998 // it will compile two branches:
6999 // the first branch will jump to the first "..:" word (or over the two branches)
7000 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
7001 // this way, each extension word will simply fix the last branch address, and update list tail
7002 // at the creation time, second branch points to the first branch
7003 UFC("FORTH:(BRANCH)");
7004 const uint32_t xjmp = UFO_GET_DP();
7005 ufoImgEmitU32(0);
7006 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp);
7007 ufoImgPutU32(xjmp, UFO_GET_DP());
7011 //==========================================================================
7013 // ufoDoneForth
7015 //==========================================================================
7016 UFO_FORCE_INLINE void ufoDoneForth (void) {
7017 UFC("FORTH:(EXIT)");
7021 //==========================================================================
7023 // ufoCompileStrLit
7025 // compile string literal, the same as QUOTE_IMM
7027 //==========================================================================
7028 static void ufoCompileStrLitEx (const char *str, const uint32_t slen) {
7029 if (str == NULL) str = "";
7030 if (slen > 255) ufoFatal("string literal too long");
7031 UFC("FORTH:(LITSTR8)");
7032 ufoImgEmitU8((uint8_t)slen);
7033 for (size_t f = 0; f < slen; f += 1) {
7034 ufoImgEmitU8(((const unsigned char *)str)[f]);
7036 ufoImgEmitU8(0);
7037 ufoImgEmitAlign();
7041 //==========================================================================
7043 // ufoCompileStrLit
7045 //==========================================================================
7047 static void ufoCompileStrLit (const char *str) {
7048 ufoCompileStrLitEx(str, (uint32_t)strlen(str));
7053 //==========================================================================
7055 // ufoCompileLit
7057 //==========================================================================
7058 static void ufoCompileLit (uint32_t value) {
7059 UFC("FORTH:(LIT)");
7060 ufoImgEmitU32(value);
7064 //==========================================================================
7066 // ufoCompileCFALit
7068 //==========================================================================
7070 static void ufoCompileCFALit (const char *wname) {
7071 UFC("FORTH:(LITCFA)");
7072 const uint32_t cfa = ufoFindWordChecked(wname);
7073 ufoImgEmitU32(cfa);
7078 //==========================================================================
7080 // ufoXStrEquCI
7082 //==========================================================================
7083 static int ufoXStrEquCI (const char *word, const char *text, uint32_t tlen) {
7084 while (tlen != 0 && *word) {
7085 if (toUpper(*word) != toUpper(*text)) return 0;
7086 word += 1u; text += 1u; tlen -= 1u;
7088 return (tlen == 0 && *word == 0);
7092 #define UFO_MAX_LABEL_NAME (63)
7093 typedef struct UfoLabel_t {
7094 uint32_t hash;
7095 uint32_t namelen;
7096 char name[UFO_MAX_LABEL_NAME];
7097 uint32_t addr; // jump chain tail, or address
7098 uint32_t defined;
7099 uint32_t word; // is this a forward word definition?
7100 struct UfoLabel_t *next;
7101 } UfoLabel;
7103 static UfoLabel *ufoLabels = NULL;
7106 //==========================================================================
7108 // ufoFindAddLabelEx
7110 //==========================================================================
7111 static UfoLabel *ufoFindAddLabelEx (const char *name, uint32_t namelen, int allowAdd) {
7112 if (namelen == 0 || namelen > UFO_MAX_LABEL_NAME) ufoFatal("invalid label name");
7113 const uint32_t hash = joaatHashBufCI(name, namelen);
7114 UfoLabel *lbl = ufoLabels;
7115 while (lbl != NULL) {
7116 if (lbl->hash == hash && lbl->namelen == namelen) {
7117 int ok = 1;
7118 uint32_t sidx = 0;
7119 while (ok && sidx != namelen) {
7120 ok = (toUpper(name[sidx]) == toUpper(lbl->name[sidx]));
7121 sidx += 1;
7123 if (ok) return lbl;
7125 lbl = lbl->next;
7127 if (allowAdd) {
7128 // create new label
7129 lbl = calloc(1, sizeof(UfoLabel));
7130 lbl->hash = hash;
7131 lbl->namelen = namelen;
7132 memcpy(lbl->name, name, namelen);
7133 lbl->name[namelen] = 0;
7134 lbl->next = ufoLabels;
7135 ufoLabels = lbl;
7136 return lbl;
7137 } else {
7138 return NULL;
7143 //==========================================================================
7145 // ufoFindAddLabel
7147 //==========================================================================
7148 static UfoLabel *ufoFindAddLabel (const char *name, uint32_t namelen) {
7149 return ufoFindAddLabelEx(name, namelen, 1);
7153 //==========================================================================
7155 // ufoFindLabel
7157 //==========================================================================
7158 static UfoLabel *ufoFindLabel (const char *name, uint32_t namelen) {
7159 return ufoFindAddLabelEx(name, namelen, 0);
7163 //==========================================================================
7165 // ufoTrySimpleNumber
7167 // only decimal and C-like hexes; with an optional sign
7169 //==========================================================================
7170 static int ufoTrySimpleNumber (const char *text, uint32_t tlen, uint32_t *num) {
7171 int neg = 0;
7173 if (tlen != 0 && *text == '+') { text += 1u; tlen -= 1u; }
7174 else if (tlen != 0 && *text == '-') { neg = 1; text += 1u; tlen -= 1u; }
7176 int base = 10; // default base
7177 if (tlen > 2 && text[0] == '0' && toUpper(text[1]) == 'X') {
7178 // hex
7179 base = 16;
7180 text += 2u; tlen -= 2u;
7183 if (tlen == 0 || digitInBase(*text, base) < 0) return 0;
7185 int wasDigit = 0;
7186 uint32_t n = 0;
7187 int dig;
7188 while (tlen != 0) {
7189 if (*text == '_') {
7190 if (!wasDigit) return 0;
7191 wasDigit = 0;
7192 } else {
7193 dig = digitInBase(*text, base);
7194 if (dig < 0) return 0;
7195 wasDigit = 1;
7196 n = n * (uint32_t)base + (uint32_t)dig;
7198 text += 1u; tlen -= 1u;
7201 if (!wasDigit) return 0;
7202 if (neg) n = ~n + 1u;
7203 *num = n;
7204 return 1;
7208 //==========================================================================
7210 // ufoEmitLabelChain
7212 //==========================================================================
7213 static void ufoEmitLabelChain (UfoLabel *lbl) {
7214 ufo_assert(lbl != NULL);
7215 ufo_assert(lbl->defined == 0);
7216 const uint32_t here = UFO_GET_DP();
7217 ufoImgEmitU32(lbl->addr);
7218 lbl->addr = here;
7222 //==========================================================================
7224 // ufoFixLabelChainHere
7226 //==========================================================================
7227 static void ufoFixLabelChainHere (UfoLabel *lbl) {
7228 ufo_assert(lbl != NULL);
7229 ufo_assert(lbl->defined == 0);
7230 const uint32_t here = UFO_GET_DP();
7231 while (lbl->addr != 0) {
7232 const uint32_t aprev = ufoImgGetU32(lbl->addr);
7233 ufoImgPutU32(lbl->addr, here);
7234 lbl->addr = aprev;
7236 lbl->addr = here;
7237 lbl->defined = 1;
7241 #define UFO_MII_WORD_COMPILE_IMM (-4)
7242 #define UFO_MII_WORD_CFA_LIT (-3)
7243 #define UFO_MII_WORD_COMPILE (-2)
7244 #define UFO_MII_IN_WORD (-1)
7245 #define UFO_MII_NO_WORD (0)
7246 #define UFO_MII_WORD_NAME (1)
7247 #define UFO_MII_WORD_NAME_IMM (2)
7248 #define UFO_MII_WORD_NAME_HIDDEN (3)
7250 static int ufoMinInterpState = UFO_MII_NO_WORD;
7253 //==========================================================================
7255 // ufoFinalLabelCheck
7257 //==========================================================================
7258 static void ufoFinalLabelCheck (void) {
7259 int errorCount = 0;
7260 if (ufoMinInterpState != UFO_MII_NO_WORD) {
7261 ufoFatal("missing semicolon");
7263 while (ufoLabels != NULL) {
7264 UfoLabel *lbl = ufoLabels; ufoLabels = lbl->next;
7265 if (!lbl->defined) {
7266 fprintf(stderr, "UFO ERROR: label '%s' is not defined!\n", lbl->name);
7267 errorCount += 1;
7269 free(lbl);
7271 if (errorCount != 0) {
7272 ufoFatal("%d undefined label%s", errorCount, (errorCount != 1 ? "s" : ""));
7277 //==========================================================================
7279 // ufoInterpretLine
7281 // this is so i could write Forth definitions more easily
7283 // labels:
7284 // $name -- reference
7285 // $name: -- definition
7287 //==========================================================================
7288 UFO_DISABLE_INLINE void ufoInterpretLine (const char *line) {
7289 char wname[UFO_MAX_WORD_LENGTH];
7290 uint32_t wlen, num, cfa;
7291 UfoLabel *lbl;
7292 while (*line) {
7293 if (*(const unsigned char *)line <= 32) {
7294 line += 1;
7295 } else if (ufoMinInterpState == UFO_MII_WORD_CFA_LIT ||
7296 ufoMinInterpState == UFO_MII_WORD_COMPILE ||
7297 ufoMinInterpState == UFO_MII_WORD_COMPILE_IMM)
7299 // "[']"/"COMPILE"/"[COMPILE]" argument
7300 wlen = 1;
7301 while (((const unsigned char *)line)[wlen] > 32) wlen += 1;
7302 if (wlen >= UFO_MAX_WORD_LENGTH) ufoFatal("word name too long");
7303 memcpy(wname, line, wlen);
7304 wname[wlen] = 0;
7305 switch (ufoMinInterpState) {
7306 case UFO_MII_WORD_CFA_LIT: UFC("FORTH:(LITCFA)"); break;
7307 case UFO_MII_WORD_COMPILE: UFC("FORTH:(LITCFA)"); break;
7308 case UFO_MII_WORD_COMPILE_IMM: break;
7309 default: ufo_assert(0);
7311 cfa = ufoFindWord(wname);
7312 if (cfa != 0) {
7313 ufoImgEmitU32(cfa);
7314 } else {
7315 // forward reference
7316 lbl = ufoFindAddLabel(line, wlen);
7317 if (lbl->defined || (lbl->word == 0 && lbl->addr)) {
7318 ufoFatal("unknown word: '%s'", wname);
7320 lbl->word = 1;
7321 ufoEmitLabelChain(lbl);
7323 switch (ufoMinInterpState) {
7324 case UFO_MII_WORD_CFA_LIT: break;
7325 case UFO_MII_WORD_COMPILE: UFC("FORTH:COMPILE,"); break;
7326 case UFO_MII_WORD_COMPILE_IMM: break;
7327 default: ufo_assert(0);
7329 ufoMinInterpState = UFO_MII_IN_WORD;
7330 line += wlen;
7331 } else if (ufoMinInterpState > UFO_MII_NO_WORD) {
7332 // new word
7333 wlen = 1;
7334 while (((const unsigned char *)line)[wlen] > 32) wlen += 1;
7335 if (wlen >= UFO_MAX_WORD_LENGTH) ufoFatal("word name too long");
7336 if (wlen > 2 && line[0] == ':' && line[wlen - 1u] == ':') ufoFatal("invalid word name");
7337 memcpy(wname, line, wlen);
7338 wname[wlen] = 0;
7339 const uint32_t oldFlags = ufoImgGetU32(ufoAddrNewWordFlags);
7340 if (ufoMinInterpState == UFO_MII_WORD_NAME_HIDDEN) {
7341 ufoImgPutU32(ufoAddrNewWordFlags, oldFlags | UFW_FLAG_HIDDEN);
7343 ufoDefineNative(wname, ufoDoForthCFA, (ufoMinInterpState == UFO_MII_WORD_NAME_IMM));
7344 ufoImgPutU32(ufoAddrNewWordFlags, oldFlags);
7345 ufoMinInterpState = UFO_MII_IN_WORD;
7346 // check for forward references
7347 lbl = ufoFindLabel(line, wlen);
7348 if (lbl != NULL) {
7349 if (lbl->defined || !lbl->word) {
7350 ufoFatal("label/word conflict for '%.*s'", (unsigned)wlen, line);
7352 ufoFixLabelChainHere(lbl);
7354 line += wlen;
7355 } else if ((line[0] == ';' && line[1] == ';') ||
7356 (line[0] == '-' && line[1] == '-') ||
7357 (line[0] == '/' && line[1] == '/') ||
7358 (line[0] == '\\' && ((const unsigned char *)line)[1] <= 32))
7360 ufoFatal("do not use single-line comments");
7361 } else if (line[0] == '(' && ((const unsigned char *)line)[1] <= 32) {
7362 while (*line && *line != ')') line += 1;
7363 if (*line == ')') line += 1;
7364 } else {
7365 // word
7366 wlen = 1;
7367 while (((const unsigned char *)line)[wlen] > 32) wlen += 1;
7368 if (wlen == 1 && (line[0] == '"' || line[0] == '`')) {
7369 // string literal
7370 const char qch = line[0];
7371 if (!line[1]) ufoFatal("unterminated string literal");
7372 // skip quote and space
7373 if (((const unsigned char *)line)[1] <= 32) line += 2u; else line += 1u;
7374 wlen = 0;
7375 while (line[wlen] && line[wlen] != qch) wlen += 1u;
7376 if (line[wlen] != qch) ufoFatal("unterminated string literal");
7377 ufoCompileStrLitEx(line, wlen);
7378 line += wlen + 1u; // skip final quote
7379 } else if (wlen == 1 && line[0] == ':') {
7380 // new word
7381 if (ufoMinInterpState != UFO_MII_NO_WORD) ufoFatal("unexpected colon");
7382 ufoMinInterpState = UFO_MII_WORD_NAME;
7383 line += wlen;
7384 } else if (wlen == 1 && line[0] == ';') {
7385 // end word
7386 if (ufoMinInterpState != UFO_MII_IN_WORD) ufoFatal("unexpected semicolon");
7387 ufoImgEmitU32(ufoFindWordChecked("FORTH:(EXIT)"));
7388 ufoMinInterpState = UFO_MII_NO_WORD;
7389 line += wlen;
7390 } else if (wlen == 2 && line[0] == '!' && line[1] == ':') {
7391 // new immediate word
7392 if (ufoMinInterpState != UFO_MII_NO_WORD) ufoFatal("unexpected colon");
7393 ufoMinInterpState = UFO_MII_WORD_NAME_IMM;
7394 line += wlen;
7395 } else if (wlen == 2 && line[0] == '*' && line[1] == ':') {
7396 // new hidden word
7397 if (ufoMinInterpState != UFO_MII_NO_WORD) ufoFatal("unexpected colon");
7398 ufoMinInterpState = UFO_MII_WORD_NAME_HIDDEN;
7399 line += wlen;
7400 } else if (wlen == 3 && memcmp(line, "[']", 3) == 0) {
7401 // cfa literal
7402 if (ufoMinInterpState != UFO_MII_IN_WORD) ufoFatal("unexpected immediate tick");
7403 ufoMinInterpState = UFO_MII_WORD_CFA_LIT;
7404 line += wlen;
7405 } else if (wlen == 7 && ufoXStrEquCI("COMPILE", line, wlen)) {
7406 // "COMPILE"
7407 if (ufoMinInterpState != UFO_MII_IN_WORD) ufoFatal("unexpected immediate tick");
7408 ufoMinInterpState = UFO_MII_WORD_COMPILE;
7409 line += wlen;
7410 } else if (wlen == 9 && ufoXStrEquCI("[COMPILE]", line, wlen)) {
7411 // "[COMPILE]"
7412 if (ufoMinInterpState != UFO_MII_IN_WORD) ufoFatal("unexpected immediate tick");
7413 ufoMinInterpState = UFO_MII_WORD_COMPILE_IMM;
7414 line += wlen;
7415 } else {
7416 // look for a word
7417 if (wlen >= UFO_MAX_WORD_LENGTH) ufoFatal("word name too long");
7418 memcpy(wname, line, wlen);
7419 wname[wlen] = 0;
7420 cfa = ufoFindWord(wname);
7421 if (cfa != 0) {
7422 // compile word
7423 ufoImgEmitU32(cfa);
7424 } else if (ufoTrySimpleNumber(line, wlen, &num)) {
7425 // compile numeric literal
7426 ufoCompileLit(num);
7427 } else {
7428 // unknown word, this may be a forward reference, or a label definition
7429 // label defintion starts with "$"
7430 // (there are no words starting with "$" in the initial image)
7431 if (line[0] == '$') {
7432 if (wlen == 1) ufoFatal("dollar what?");
7433 if (wlen > 2 && line[wlen - 1u] == ':') {
7434 // label definition
7435 lbl = ufoFindAddLabel(line, wlen - 1u);
7436 if (lbl->defined) ufoFatal("double label '%s' definition", lbl->name);
7437 ufoFixLabelChainHere(lbl);
7438 } else {
7439 // label reference
7440 lbl = ufoFindAddLabel(line, wlen);
7441 if (lbl->defined) {
7442 ufoImgEmitU32(lbl->addr);
7443 } else {
7444 ufoEmitLabelChain(lbl);
7447 } else {
7448 // forward reference
7449 lbl = ufoFindAddLabel(line, wlen);
7450 if (lbl->defined || (lbl->word == 0 && lbl->addr)) {
7451 ufoFatal("unknown word: '%s'", wname);
7453 lbl->word = 1;
7454 ufoEmitLabelChain(lbl);
7457 line += wlen;
7464 //==========================================================================
7466 // ufoReset
7468 //==========================================================================
7469 UFO_DISABLE_INLINE void ufoReset (void) {
7470 if (ufoCurrState == NULL) ufoFatal("no active execution state");
7472 ufoSP = 0; ufoRP = 0;
7473 ufoLP = 0; ufoLBP = 0;
7475 ufoInRunWord = 0;
7476 ufoVMStop = 0; ufoVMAbort = 0;
7478 ufoInBacktrace = 0;
7480 // save TIB
7481 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
7482 const uint32_t tibDef = ufoImgGetU32(ufoAddrDefTIB);
7483 ufoInitStateUserVars(ufoCurrState, 0);
7484 // restore TIB
7485 ufoImgPutU32(ufoAddrTIBx, tib);
7486 ufoImgPutU32(ufoAddrDefTIB, tibDef);
7487 ufoImgPutU32(ufoAddrRedefineWarning, UFO_REDEF_WARN_NORMAL);
7488 ufoResetTib();
7490 ufoImgPutU32(ufoAddrDPTemp, 0);
7492 ufoImgPutU32(ufoAddrNewWordFlags, 0);
7493 ufoVocSetOnlyDefs(ufoForthVocId);
7497 //==========================================================================
7499 // ufoDefineEmitType
7501 //==========================================================================
7502 UFO_DISABLE_INLINE void ufoDefineEmitType (void) {
7503 // EMIT
7504 // ( ch -- )
7505 ufoInterpretLine(": EMIT ( ch -- ) (NORM-EMIT-CHAR) (EMIT) ;");
7507 // XEMIT
7508 // ( ch -- )
7509 ufoInterpretLine(": XEMIT ( ch -- ) (NORM-XEMIT-CHAR) (EMIT) ;");
7511 // CR
7512 // ( -- )
7513 ufoInterpretLine(": CR ( -- ) NL (EMIT) ;");
7515 // ENDCR
7516 // ( -- )
7517 ufoInterpretLine(
7518 ": ENDCR ( -- ) "
7519 " LASTCR? FORTH:(TBRANCH) $endcr-exit CR "
7520 "$endcr-exit: "
7521 ";");
7522 //ufoDecompileWord(ufoFindWordChecked("ENDCR"));
7524 // SPACE
7525 // ( -- )
7526 ufoInterpretLine(": SPACE ( -- ) BL (EMIT) ;");
7528 // SPACES
7529 // ( count -- )
7530 ufoInterpretLine(
7531 ": SPACES ( count -- ) "
7532 "$spaces-again: "
7533 " DUP 0> FORTH:(0BRANCH) $spaces-exit "
7534 " SPACE 1- "
7535 " FORTH:(BRANCH) $spaces-again "
7536 "$spaces-exit: "
7537 " DROP "
7538 ";");
7540 // TYPE
7541 // ( addr count -- )
7542 ufoInterpretLine(
7543 ": TYPE ( addr count -- ) "
7544 " A>R SWAP >A "
7545 "$type-again: "
7546 " DUP 0> FORTH:(0BRANCH) $type-exit "
7547 " C@A EMIT +1>A "
7548 " 1- "
7549 " FORTH:(BRANCH) $type-again "
7550 "$type-exit: "
7551 " DROP R>A "
7552 ";");
7554 // XTYPE
7555 // ( addr count -- )
7556 ufoInterpretLine(
7557 ": XTYPE ( addr count -- ) "
7558 " A>R SWAP >A "
7559 "$xtype-again: "
7560 " DUP 0> FORTH:(0BRANCH) $xtype-exit "
7561 " C@A XEMIT +1>A "
7562 " 1- "
7563 " FORTH:(BRANCH) $xtype-again "
7564 "$xtype-exit: "
7565 " DROP R>A "
7566 ";");
7568 // HERE
7569 // ( -- here )
7570 ufoInterpretLine(
7571 ": HERE ( -- here ) "
7572 " FORTH:(DP-TEMP) @ ?DUP "
7573 " FORTH:(TBRANCH) $here-exit "
7574 " FORTH:(DP) @ "
7575 "$here-exit: "
7576 ";");
7578 // ALIGN-HERE
7579 // ( -- )
7580 ufoInterpretLine(
7581 ": ALIGN-HERE ( -- ) "
7582 "$align-here-loop: "
7583 " HERE 3 AND "
7584 " FORTH:(0BRANCH) $align-here-exit "
7585 " 0 C, "
7586 " FORTH:(BRANCH) $align-here-loop "
7587 "$align-here-exit: "
7588 ";");
7590 // STRLITERAL
7591 // ( C:addr count -- ) ( E: -- addr count )
7592 ufoInterpretLine(
7593 ": STRLITERAL ( C:addr count -- ) ( E: -- addr count ) "
7594 " DUP 255 U> ` string literal too long` ?ERROR "
7595 " STATE @ FORTH:(0BRANCH) $strlit-exit "
7596 " ( addr count ) "
7597 " ['] FORTH:(LITSTR8) COMPILE, "
7598 " A>R SWAP >A "
7599 " ( compile length ) "
7600 " DUP C, "
7601 " ( compile chars ) "
7602 "$strlit-loop: "
7603 " DUP 0<> FORTH:(0BRANCH) $strlit-loop-exit "
7604 " C@A C, +1>A 1- "
7605 " FORTH:(BRANCH) $strlit-loop "
7606 "$strlit-loop-exit: "
7607 " R>A "
7608 " ( final 0: our counter is 0 here, so use it ) "
7609 " C, ALIGN-HERE "
7610 "$strlit-exit: "
7611 ";");
7613 // quote
7614 // ( -- addr count )
7615 ufoInterpretLine(
7616 "!: \" ( -- addr count ) "
7617 " 34 PARSE ` string literal expected` ?NOT-ERROR "
7618 " COMPILER:(UNESCAPE) STRLITERAL "
7619 ";");
7623 //==========================================================================
7625 // ufoDefineInterpret
7627 // define "INTERPRET" in Forth
7629 //==========================================================================
7630 UFO_DISABLE_INLINE void ufoDefineInterpret (void) {
7631 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION);
7633 // return "stop flag"
7634 ufoInterpretLine(
7635 "*: (UFO-INTERPRET-NEXT-LINE) ( -- continue? ) "
7636 " STATE @ FORTH:(TBRANCH) $ipn_incomp "
7637 " ( interpreter allowed to cross include boundary ) "
7638 " REFILL FORTH:(BRANCH) $ipn_done "
7639 "$ipn_incomp: "
7640 " ( compiler is not allowed to cross include boundary ) "
7641 " REFILL-NOCROSS ` compiler cannot cross file boundaries` ?NOT-ERROR "
7642 " TRUE "
7643 "$ipn_done: "
7644 ";");
7646 ufoInterpNextLineCFA = ufoFindWordChecked("FORTH:(UFO-INTERPRET-NEXT-LINE)");
7647 ufoInterpretLine("*: (INTERPRET-NEXT-LINE) (USER-INTERPRET-NEXT-LINE) @ EXECUTE-TAIL ;");
7649 // skip comments, parse name, refilling lines if necessary
7650 // returning FALSE as counter means: "no addr, exit INTERPRET"
7651 ufoInterpretLine(
7652 "*: (INTERPRET-PARSE-NAME) ( -- addr count / FALSE ) "
7653 "$label_ipn_again: "
7654 " TRUE (PARSE-SKIP-COMMENTS) PARSE-NAME "
7655 " DUP FORTH:(TBRANCH) $label_ipn_exit_fwd "
7656 " 2DROP (INTERPRET-NEXT-LINE) "
7657 " FORTH:(TBRANCH) $label_ipn_again "
7658 " FALSE "
7659 "$label_ipn_exit_fwd: "
7660 ";");
7661 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
7663 ufoInterpretLine(
7664 ": INTERPRET "
7665 "$interp-again: "
7666 " FORTH:(INTERPRET-PARSE-NAME) ( addr count / FALSE )"
7667 " ?DUP FORTH:(0BRANCH) $interp-done "
7668 " ( try defered checker ) "
7669 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7670 " FALSE (INTERPRET-CHECK-WORD) FORTH:(TBRANCH) $interp-again "
7671 " 2DUP FIND-WORD ( addr count cfa TRUE / addr count FALSE ) "
7672 " FORTH:(0BRANCH) $interp-try-number "
7673 " ( word found ) "
7674 " NROT 2DROP ( drop word string ) "
7675 " STATE @ FORTH:(0BRANCH) $interp-exec "
7676 " ( compiling; check immediate bit ) "
7677 " DUP CFA->NFA @ COMPILER:(WFLAG-IMMEDIATE) AND FORTH:(TBRANCH) $interp-exec "
7678 " ( compile it ) "
7679 " FORTH:COMPILE, FORTH:(BRANCH) $interp-again "
7680 " ( execute it ) "
7681 "$interp-exec: "
7682 " EXECUTE FORTH:(BRANCH) $interp-again "
7683 " ( not a word, try a number ) "
7684 "$interp-try-number: "
7685 " 2DUP TRUE BASE @ (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE ) "
7686 " FORTH:(0BRANCH) $interp-number-error "
7687 " ( number ) "
7688 " NROT 2DROP ( drop word string ) "
7689 " ( do we need to compile it? ) "
7690 " STATE @ FORTH:(0BRANCH) $interp-again "
7691 " COMPILE FORTH:(LIT) FORTH:, "
7692 " FORTH:(BRANCH) $interp-again "
7693 " ( error ) "
7694 "$interp-number-error: "
7695 " ( addr count FALSE -- addr count FALSE / TRUE ) "
7696 " FALSE (INTERPRET-WORD-NOT-FOUND) FORTH:(TBRANCH) $interp-again "
7697 " ENDCR SPACE XTYPE ` -- wut?` TYPE CR "
7698 " ` unknown word` ERROR "
7699 "$interp-done: "
7700 ";");
7701 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
7705 //==========================================================================
7707 // ufoInitBaseDict
7709 //==========================================================================
7710 UFO_DISABLE_INLINE void ufoInitBaseDict (void) {
7711 uint32_t imgAddr = 0;
7713 // reserve 32 bytes for nothing
7714 for (uint32_t f = 0; f < 32; f += 1) {
7715 ufoImgPutU8(imgAddr, 0);
7716 imgAddr += 1;
7718 // align
7719 while ((imgAddr & 3) != 0) {
7720 ufoImgPutU8(imgAddr, 0);
7721 imgAddr += 1;
7724 // DP
7725 ufoAddrDP = imgAddr;
7726 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
7728 // DP-TEMP
7729 ufoAddrDPTemp = imgAddr;
7730 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
7732 // (LATEST-XFA)
7733 ufoAddrLastXFA = imgAddr;
7734 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
7736 // (VOC-LINK)
7737 ufoAddrVocLink = imgAddr;
7738 ufoImgPutU32(imgAddr, 0); imgAddr += 4u;
7740 // (NEW-WORD-FLAGS)
7741 ufoAddrNewWordFlags = imgAddr;
7742 ufoImgPutU32(imgAddr, UFW_FLAG_PROTECTED); imgAddr += 4u;
7744 // WORD-REDEFINE-WARN-MODE
7745 ufoAddrRedefineWarning = imgAddr;
7746 ufoImgPutU32(imgAddr, UFO_REDEF_WARN_NORMAL); imgAddr += 4u;
7748 // setup (DP) and (DP-TEMP)
7749 ufoImgPutU32(ufoAddrDP, imgAddr);
7750 ufoImgPutU32(ufoAddrDPTemp, 0);
7752 #if 0
7753 fprintf(stderr, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr, UFO_GET_DP());
7754 #endif
7758 //==========================================================================
7760 // ufoInitStateUserVars
7762 //==========================================================================
7763 static void ufoInitStateUserVars (UfoState *st, uint32_t cfa) {
7764 ufo_assert(st != NULL);
7765 if (st->imageTempSize < 8192u) {
7766 uint32_t *itmp = realloc(st->imageTemp, 8192);
7767 if (itmp == NULL) ufoFatal("out of memory for state user area");
7768 st->imageTemp = itmp;
7769 memset((uint8_t *)st->imageTemp + st->imageTempSize, 0, 8192u - st->imageTempSize);
7770 st->imageTempSize = 8192;
7772 st->imageTemp[(ufoAddrBASE & UFO_ADDR_TEMP_MASK) / 4u] = 10;
7773 st->imageTemp[(ufoAddrSTATE & UFO_ADDR_TEMP_MASK) / 4u] = 0;
7774 st->imageTemp[(ufoAddrUserVarUsed & UFO_ADDR_TEMP_MASK) / 4u] = ufoAddrUserVarUsed;
7775 st->imageTemp[(ufoAddrDefTIB & UFO_ADDR_TEMP_MASK) / 4u] = UFO_DEF_TIB_ADDR;
7776 st->imageTemp[(ufoAddrTIBx & UFO_ADDR_TEMP_MASK) / 4u] = UFO_DEF_TIB_ADDR;
7777 st->imageTemp[(ufoAddrINx & UFO_ADDR_TEMP_MASK) / 4u] = 0;
7778 st->imageTemp[(ufoAddrContext & UFO_ADDR_TEMP_MASK) / 4u] = ufoForthVocId;
7779 st->imageTemp[(ufoAddrCurrent & UFO_ADDR_TEMP_MASK) / 4u] = ufoForthVocId;
7780 st->imageTemp[(ufoAddrSelf & UFO_ADDR_TEMP_MASK) / 4u] = 0;
7781 st->imageTemp[(ufoAddrInterNextLine & UFO_ADDR_TEMP_MASK) / 4u] = ufoInterpNextLineCFA;
7782 st->imageTemp[(ufoAddrEP & UFO_ADDR_TEMP_MASK) / 4u] = 0;
7783 // init other things, because this procedure is used in `ufoReset()` too
7784 st->SP = 0; st->RP = 0; st->RPTop = 0; st->regA = 0;
7785 st->LP = 0; st->LBP = 0; st->vmRPopCFA = 0;
7786 st->VSP = 0;
7787 // init it
7788 if (cfa != 0) {
7789 st->vmRPopCFA = 1;
7790 st->rStack[0] = 0xdeadf00d; // dummy value
7791 st->rStack[1] = cfa;
7792 st->RP = 2;
7797 //==========================================================================
7799 // ufoInitBasicWords
7801 //==========================================================================
7802 UFO_DISABLE_INLINE void ufoInitBasicWords (void) {
7803 ufoDefineConstant("FALSE", 0);
7804 ufoDefineConstant("TRUE", ufoTrueValue);
7806 ufoDefineConstant("BL", 32);
7807 ufoDefineConstant("NL", 10);
7809 // user variables
7810 ufoDefineUserVar("BASE", ufoAddrBASE);
7811 ufoDefineUserVar("TIB", ufoAddrTIBx);
7812 ufoDefineUserVar(">IN", ufoAddrINx);
7813 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB);
7814 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed);
7815 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT);
7816 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE);
7817 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR);
7818 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK);
7820 ufoDefineUserVar("STATE", ufoAddrSTATE);
7821 ufoDefineConstant("CONTEXT", ufoAddrContext);
7822 ufoDefineConstant("CURRENT", ufoAddrCurrent);
7823 ufoDefineConstant("(SELF)", ufoAddrSelf); // used in OOP implementations
7824 ufoDefineConstant("(USER-INTERPRET-NEXT-LINE)", ufoAddrInterNextLine);
7825 ufoDefineConstant("(EXC-FRAME-PTR)", ufoAddrEP);
7827 ufoHiddenWords();
7828 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA);
7829 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink);
7830 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags);
7831 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT);
7832 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT);
7833 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT);
7834 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK);
7836 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR);
7837 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR + 4u); // reserve room for counter
7838 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE - 8u);
7840 ufoDefineConstant("(DP)", ufoAddrDP);
7841 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp);
7842 ufoPublicWords();
7844 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
7845 UFWORDX("SP0!", SP0_STORE);
7846 UFWORDX("RP0!", RP0_STORE);
7848 UFWORDX("PAD", PAD);
7850 UFWORDX("@", PEEK);
7851 UFWORDX("C@", CPEEK);
7852 UFWORDX("W@", WPEEK);
7854 UFWORDX("!", POKE);
7855 UFWORDX("C!", CPOKE);
7856 UFWORDX("W!", WPOKE);
7858 UFWORDX(",", COMMA);
7859 UFWORDX("C,", CCOMMA);
7860 UFWORDX("W,", WCOMMA);
7862 UFWORDX("A>", REGA_LOAD);
7863 UFWORDX(">A", REGA_STORE);
7864 UFWORDX("A-SWAP", REGA_SWAP);
7865 UFWORDX("+1>A", REGA_INC);
7866 UFWORDX("+4>A", REGA_INC_CELL);
7867 UFWORDX("A>R", REGA_TO_R);
7868 UFWORDX("R>A", R_TO_REGA);
7870 UFWORDX("@A+", PEEK_REGA_IDX);
7871 UFWORDX("C@A+", CPEEK_REGA_IDX);
7872 UFWORDX("W@A+", WPEEK_REGA_IDX);
7874 UFWORDX("!A+", POKE_REGA_IDX);
7875 UFWORDX("C!A+", CPOKE_REGA_IDX);
7876 UFWORDX("W!A+", WPOKE_REGA_IDX);
7878 ufoHiddenWords();
7879 UFWORDX("(LIT)", PAR_LIT); ufoSetLatestArgs(UFW_WARG_LIT);
7880 UFWORDX("(LITCFA)", PAR_LITCFA); ufoSetLatestArgs(UFW_WARG_CFA);
7881 UFWORDX("(LITVOCID)", PAR_LITVOCID); ufoSetLatestArgs(UFW_WARG_VOCID);
7882 UFWORDX("(LITSTR8)", PAR_LITSTR8); ufoSetLatestArgs(UFW_WARG_C1STRZ);
7883 UFWORDX("(EXIT)", PAR_EXIT);
7885 ufoLitStr8CFA = ufoFindWordChecked("FORTH:(LITSTR8)");
7887 UFWORDX("(L-ENTER)", PAR_LENTER); ufoSetLatestArgs(UFW_WARG_LIT);
7888 UFWORDX("(L-LEAVE)", PAR_LLEAVE);
7889 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD);
7890 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE);
7892 UFWORDX("(BRANCH)", PAR_BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7893 UFWORDX("(TBRANCH)", PAR_TBRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7894 UFWORDX("(0BRANCH)", PAR_0BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7895 UFWORDX("(+0BRANCH)", PAR_P0BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7896 UFWORDX("(+BRANCH)", PAR_PBRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7897 UFWORDX("(-0BRANCH)", PAR_M0BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7898 UFWORDX("(-BRANCH)", PAR_MBRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7899 UFWORDX("(DATASKIP)", PAR_DATASKIP); ufoSetLatestArgs(UFW_WARG_DATASKIP);
7900 UFWORDX("(OR-BRANCH)", PAR_OR_BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7901 UFWORDX("(AND-BRANCH)", PAR_AND_BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7902 UFWORDX("(CASE-BRANCH)", PAR_CASE_BRANCH); ufoSetLatestArgs(UFW_WARG_BRANCH);
7903 ufoPublicWords();
7907 //==========================================================================
7909 // ufoInitBasicCompilerWords
7911 //==========================================================================
7912 UFO_DISABLE_INLINE void ufoInitBasicCompilerWords (void) {
7913 // create "COMPILER" vocabulary
7914 ufoCompilerVocId = ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED);
7915 ufoVocSetOnlyDefs(ufoCompilerVocId);
7917 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA);
7918 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA);
7919 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA);
7920 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA);
7921 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA);
7922 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA);
7923 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA);
7924 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA);
7926 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE);
7927 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE);
7928 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN);
7929 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN);
7930 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK);
7931 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB);
7932 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON);
7933 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED);
7935 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK);
7936 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE);
7937 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH);
7938 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT);
7939 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ);
7940 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA);
7941 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK);
7942 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID);
7943 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ);
7945 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST);
7946 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK);
7947 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT);
7948 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER);
7949 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE);
7950 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE);
7951 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG);
7953 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE);
7954 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE);
7955 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL);
7956 ufoDefineConstant("(REDEFINE-WARN-PARENTS)", UFO_REDEF_WARN_PARENTS);
7958 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning);
7960 UFWORDX("(UNESCAPE)", PAR_UNESCAPE);
7962 ufoInterpretLine(
7963 ": ?EXEC ( -- ) "
7964 " FORTH:STATE FORTH:@ ` expecting interpretation mode` FORTH:?ERROR "
7965 ";");
7967 ufoInterpretLine(
7968 ": ?COMP ( -- ) "
7969 " FORTH:STATE FORTH:@ ` expecting compilation mode` FORTH:?NOT-ERROR "
7970 ";");
7972 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER);
7973 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER);
7975 ufoVocSetOnlyDefs(ufoForthVocId);
7977 // [
7978 ufoInterpretLine("!: [ COMPILER:?COMP 0 STATE ! ;");
7979 // ]
7980 ufoInterpretLine(": ] COMPILER:?EXEC 1 STATE ! ;");
7984 //==========================================================================
7986 // ufoInitMoreWords
7988 //==========================================================================
7989 UFO_DISABLE_INLINE void ufoInitMoreWords (void) {
7990 UFWORDX("COMPILE,", COMMA); // just an alias, for clarity
7992 UFWORDX("CFA->PFA", CFA2PFA);
7993 UFWORDX("CFA->NFA", CFA2NFA);
7994 UFWORDX("CFA->LFA", CFA2LFA);
7995 UFWORDX("CFA->WEND", CFA2WEND);
7997 UFWORDX("PFA->CFA", PFA2CFA);
7998 UFWORDX("PFA->NFA", PFA2NFA);
8000 UFWORDX("NFA->CFA", NFA2CFA);
8001 UFWORDX("NFA->PFA", NFA2PFA);
8002 UFWORDX("NFA->LFA", NFA2LFA);
8004 UFWORDX("LFA->CFA", LFA2CFA);
8005 UFWORDX("LFA->PFA", LFA2PFA);
8006 UFWORDX("LFA->BFA", LFA2BFA);
8007 UFWORDX("LFA->XFA", LFA2XFA);
8008 UFWORDX("LFA->YFA", LFA2YFA);
8009 UFWORDX("LFA->NFA", LFA2NFA);
8011 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER);
8012 UFWORDX("FIND-WORD", FIND_WORD);
8013 UFWORDX("(FIND-WORD-IN-VOC)", FIND_WORD_IN_VOC);
8014 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", FIND_WORD_IN_VOC_AND_PARENTS);
8016 UFWORD(EXECUTE);
8017 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL);
8018 UFWORDX("(FORTH-CALL)", FORTH_CALL);
8020 UFWORD(DUP);
8021 UFWORDX("?DUP", QDUP);
8022 UFWORDX("2DUP", DDUP);
8023 UFWORD(DROP);
8024 UFWORDX("2DROP", DDROP);
8025 UFWORD(SWAP);
8026 UFWORDX("2SWAP", DSWAP);
8027 UFWORD(OVER);
8028 UFWORDX("2OVER", DOVER);
8029 UFWORD(ROT);
8030 UFWORD(NROT);
8031 UFWORDX("PICK", PICK);
8032 UFWORDX("ROLL", ROLL);
8034 UFWORD(RDUP);
8035 UFWORD(RDROP);
8036 UFWORDX(">R", DTOR);
8037 UFWORDX("R>", RTOD);
8038 UFWORDX("R@", RPEEK);
8039 UFWORDX("RPICK", RPICK);
8040 UFWORDX("RROLL", RROLL);
8041 UFWORDX("RSWAP", RSWAP);
8042 UFWORDX("ROVER", ROVER);
8043 UFWORDX("RROT", RROT);
8044 UFWORDX("RNROT", RNROT);
8046 UFWORDX("FLUSH-EMIT", FLUSH_EMIT);
8047 UFWORDX("(EMIT)", PAR_EMIT);
8048 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR);
8049 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR);
8050 UFWORDX("LASTCR?", LASTCRQ);
8051 UFWORDX("LASTCR!", LASTCRSET);
8053 // simple math
8054 UFWORDX("+", PLUS);
8055 UFWORDX("-", MINUS);
8056 UFWORDX("*", MUL);
8057 UFWORDX("U*", UMUL);
8058 UFWORDX("/", DIV);
8059 UFWORDX("U/", UDIV);
8060 UFWORDX("MOD", MOD);
8061 UFWORDX("UMOD", UMOD);
8062 UFWORDX("/MOD", DIVMOD);
8063 UFWORDX("U/MOD", UDIVMOD);
8064 UFWORDX("*/", MULDIV);
8065 UFWORDX("U*/", UMULDIV);
8066 UFWORDX("*/MOD", MULDIVMOD);
8067 UFWORDX("U*/MOD", UMULDIVMOD);
8068 UFWORDX("M*", MMUL);
8069 UFWORDX("UM*", UMMUL);
8070 UFWORDX("M/MOD", MDIVMOD);
8071 UFWORDX("UM/MOD", UMDIVMOD);
8072 UFWORDX("UDS*", UDSMUL);
8074 UFWORDX("SM/REM", SMREM);
8075 UFWORDX("FM/MOD", FMMOD);
8077 UFWORDX("D-", DMINUS);
8078 UFWORDX("D+", DPLUS);
8079 UFWORDX("D=", DEQU);
8080 UFWORDX("D<", DLESS);
8081 UFWORDX("D<=", DLESSEQU);
8082 UFWORDX("DU<", DULESS);
8083 UFWORDX("DU<=", DULESSEQU);
8085 UFWORD(ASH);
8086 UFWORD(LSH);
8088 // logic
8089 UFWORDX("<", LESS);
8090 UFWORDX(">", GREAT);
8091 UFWORDX("<=", LESSEQU);
8092 UFWORDX(">=", GREATEQU);
8093 UFWORDX("U<", ULESS);
8094 UFWORDX("U>", UGREAT);
8095 UFWORDX("U<=", ULESSEQU);
8096 UFWORDX("U>=", UGREATEQU);
8097 UFWORDX("=", EQU);
8098 UFWORDX("<>", NOTEQU);
8100 UFWORDX("0=", ZERO_EQU);
8101 UFWORDX("0<>", ZERO_NOTEQU);
8103 UFWORDX("NOT", ZERO_EQU);
8104 UFWORDX("NOTNOT", ZERO_NOTEQU);
8106 UFWORD(BITNOT);
8107 UFWORD(AND);
8108 UFWORD(OR);
8109 UFWORD(XOR);
8110 UFWORDX("LOGAND", LOGAND);
8111 UFWORDX("LOGOR", LOGOR);
8113 // TIB and parser
8114 UFWORDX("(TIB-IN)", TIB_IN);
8115 UFWORDX("TIB-PEEKCH", TIB_PEEKCH);
8116 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS);
8117 UFWORDX("TIB-GETCH", TIB_GETCH);
8118 UFWORDX("TIB-SKIPCH", TIB_SKIPCH);
8120 UFWORDX("REFILL", REFILL);
8121 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS);
8123 ufoHiddenWords();
8124 UFWORDX("(PARSE)", PAR_PARSE);
8125 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS);
8126 ufoPublicWords();
8127 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS);
8128 UFWORDX("PARSE-NAME", PARSE_NAME);
8129 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE);
8130 UFWORDX("PARSE", PARSE);
8132 ufoHiddenWords();
8133 UFWORDX("(VSP@)", PAR_GET_VSP);
8134 UFWORDX("(VSP!)", PAR_SET_VSP);
8135 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD);
8136 UFWORDX("(VSP-AT!)", PAR_VSP_STORE);
8137 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE);
8139 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE);
8140 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE);
8141 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE);
8142 ufoPublicWords();
8144 UFWORDX("ERROR", ERROR);
8145 UFWORDX("FATAL-ERROR", ERROR);
8147 ufoInterpretLine(": 1+ ( n -- n+1 ) 1 + ;");
8148 ufoInterpretLine(": 1- ( n -- n-1 ) 1 - ;");
8149 ufoInterpretLine(": 2+ ( n -- n+2 ) 2 + ;");
8150 ufoInterpretLine(": 2- ( n -- n-2 ) 2 - ;");
8151 ufoInterpretLine(": 4+ ( n -- n+4 ) 4 + ;");
8152 ufoInterpretLine(": 4- ( n -- n-4 ) 4 - ;");
8154 ufoInterpretLine(": 2* ( n -- n*2 ) 1 ASH ;");
8155 ufoInterpretLine(": 2/ ( n -- n/2 ) -1 ASH ;");
8156 ufoInterpretLine(": 4* ( n -- n*4 ) 2 ASH ;");
8157 ufoInterpretLine(": 4/ ( n -- n/4 ) -2 ASH ;");
8159 ufoInterpretLine(": 2U* ( u -- u*2 ) 1 LSH ;");
8160 ufoInterpretLine(": 2U/ ( u -- u/2 ) -1 LSH ;");
8161 ufoInterpretLine(": 4U* ( u -- u*4 ) 2 LSH ;");
8162 ufoInterpretLine(": 4U/ ( u -- u/4 ) -2 LSH ;");
8164 ufoInterpretLine(": 0< ( n -- n<0 ) 0 < ;");
8165 ufoInterpretLine(": 0> ( n -- n>0 ) 0 > ;");
8166 ufoInterpretLine(": 0<= ( n -- n<0 ) 0 <= ;");
8167 ufoInterpretLine(": 0>= ( n -- n>0 ) 0 >= ;");
8169 ufoInterpretLine(": @A ( idx -- v ) 0 @A+ ;");
8170 ufoInterpretLine(": C@A ( idx -- v ) 0 C@A+ ;");
8171 ufoInterpretLine(": W@A ( idx -- v ) 0 W@A+ ;");
8173 ufoInterpretLine(": !A ( idx -- v ) 0 !A+ ;");
8174 ufoInterpretLine(": C!A ( idx -- v ) 0 C!A+ ;");
8175 ufoInterpretLine(": W!A ( idx -- v ) 0 W!A+ ;");
8177 // ABORT
8178 // ( -- )
8179 ufoInterpretLine(": ABORT ` \"ABORT\" called` ERROR ;");
8181 // ?ERROR
8182 // ( errflag addr count -- )
8183 ufoInterpretLine(
8184 ": ?ERROR ( errflag addr count -- ) "
8185 " ROT FORTH:(0BRANCH) $qerr_skip ERROR "
8186 "$qerr_skip: "
8187 " 2DROP "
8188 ";");
8190 // ?NOT-ERROR
8191 // ( errflag addr count -- )
8192 ufoInterpretLine(
8193 ": ?NOT-ERROR ( errflag addr count -- ) "
8194 " ROT FORTH:(TBRANCH) $qnoterr_skip ERROR "
8195 "$qnoterr_skip: "
8196 " 2DROP "
8197 ";");
8199 ufoInterpretLine(
8200 ": FIND-WORD-IN-VOC ( vocid addr count -- cfa TRUE / FALSE ) "
8201 " 0 (FIND-WORD-IN-VOC) ;");
8203 ufoInterpretLine(
8204 ": FIND-WORD-IN-VOC-AND-PARENTS ( vocid addr count -- cfa TRUE / FALSE ) "
8205 " 0 (FIND-WORD-IN-VOC-AND-PARENTS) ;");
8207 UFWORDX("GET-MSECS", GET_MSECS);
8211 //==========================================================================
8213 // ufoInitHandleWords
8215 //==========================================================================
8216 UFO_DISABLE_INLINE void ufoInitHandleWords (void) {
8217 // create "HANDLE" vocabulary
8218 const uint32_t handleVocId = ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED);
8219 ufoVocSetOnlyDefs(handleVocId);
8220 UFWORDX("NEW", PAR_NEW_HANDLE);
8221 UFWORDX("FREE", PAR_FREE_HANDLE);
8222 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID);
8223 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID);
8224 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE);
8225 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE);
8226 UFWORDX("USED@", PAR_HANDLE_GET_USED);
8227 UFWORDX("USED!", PAR_HANDLE_SET_USED);
8228 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE);
8229 UFWORDX("W@", PAR_HANDLE_LOAD_WORD);
8230 UFWORDX("@", PAR_HANDLE_LOAD_CELL);
8231 UFWORDX("C!", PAR_HANDLE_STORE_BYTE);
8232 UFWORDX("W!", PAR_HANDLE_STORE_WORD);
8233 UFWORDX("!", PAR_HANDLE_STORE_CELL);
8234 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE);
8235 ufoVocSetOnlyDefs(ufoForthVocId);
8239 //==========================================================================
8241 // ufoInitHigherWords
8243 //==========================================================================
8244 UFO_DISABLE_INLINE void ufoInitHigherWords (void) {
8245 UFWORDX("(INCLUDE)", PAR_INCLUDE);
8246 UFWORDX("(INCLUDE-DROP)", PAR_INCLUDE_DROP);
8247 UFWORDX("(INCLUDE-BUILD-NAME)", PAR_INCLUDE_BUILD_NAME);
8248 UFWORDX("(INCLUDE-NO-REFILL)", PAR_INCLUDE_NO_REFILL);
8249 UFWORDX("(INCLUDE-LINE-SEEK)", PAR_INCLUDE_LINE_SEEK);
8251 UFWORDX("(INCLUDE-LINE-FOFS)", PAR_INCLUDE_LINE_FOFS);
8252 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH);
8253 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID);
8254 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE);
8255 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME);
8257 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ);
8258 UFWORDX("($DEFINE)", PAR_DLR_DEFINE);
8259 UFWORDX("($UNDEF)", PAR_DLR_UNDEF);
8261 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM);
8262 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM);
8266 //==========================================================================
8268 // ufoInitStringWords
8270 //==========================================================================
8271 UFO_DISABLE_INLINE void ufoInitStringWords (void) {
8272 // create "STRING" vocabulary
8273 const uint32_t stringVocId = ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED);
8274 ufoVocSetOnlyDefs(stringVocId);
8275 UFWORDX("=", STREQU);
8276 UFWORDX("=CI", STREQUCI);
8277 UFWORDX("SEARCH", SEARCH);
8278 UFWORDX("HASH", STRHASH);
8279 UFWORDX("HASH-CI", STRHASHCI);
8280 ufoVocSetOnlyDefs(ufoForthVocId);
8284 //==========================================================================
8286 // ufoInitDebugWords
8288 //==========================================================================
8289 UFO_DISABLE_INLINE void ufoInitDebugWords (void) {
8290 // create "DEBUG" vocabulary
8291 const uint32_t debugVocId = ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED);
8292 ufoVocSetOnlyDefs(debugVocId);
8293 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA);
8294 UFWORDX("(DECOMPILE-MEM)", DEBUG_DECOMPILE_MEM);
8295 UFWORDX("BACKTRACE", UFO_BACKTRACE);
8296 UFWORDX("DUMP-STACK", DUMP_STACK);
8297 UFWORDX("BACKTRACE-TASK", UFO_BACKTRACE_TASK);
8298 UFWORDX("DUMP-STACK-TASK", DUMP_STACK_TASK);
8299 UFWORDX("DUMP-RSTACK-TASK", DUMP_RSTACK_TASK);
8300 UFWORDX("(BP)", MT_DEBUGGER_BP);
8301 UFWORDX("IP->NFA", IP2NFA);
8302 UFWORDX("IP->FILE/LINE", IP2FILELINE);
8303 UFWORDX("IP->FILE-HASH/LINE", IP2FILEHASHLINE);
8304 ufoVocSetOnlyDefs(ufoForthVocId);
8308 //==========================================================================
8310 // ufoInitMTWords
8312 //==========================================================================
8313 UFO_DISABLE_INLINE void ufoInitMTWords (void) {
8314 // create "MTASK" vocabulary
8315 const uint32_t mtVocId = ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED);
8316 ufoVocSetOnlyDefs(mtVocId);
8317 UFWORDX("NEW-STATE", MT_NEW_STATE);
8318 UFWORDX("FREE-STATE", MT_FREE_STATE);
8319 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME);
8320 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME);
8321 UFWORDX("STATE-FIRST", MT_STATE_FIRST);
8322 UFWORDX("STATE-NEXT", MT_STATE_NEXT);
8323 UFWORDX("YIELD-TO", MT_YIELD_TO);
8324 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER);
8325 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE);
8326 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE);
8327 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE);
8328 UFWORDX("STATE-IP@", MT_STATE_IP_GET);
8329 UFWORDX("STATE-IP!", MT_STATE_IP_SET);
8330 UFWORDX("STATE-A>", MT_STATE_REGA_GET);
8331 UFWORDX("STATE->A", MT_STATE_REGA_SET);
8332 UFWORDX("STATE-USER@", MT_STATE_USER_GET);
8333 UFWORDX("STATE-USER!", MT_STATE_USER_SET);
8334 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET);
8335 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET);
8336 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM);
8337 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET);
8338 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET);
8339 UFWORDX("STATE-LP@", MT_LP_GET);
8340 UFWORDX("STATE-LBP@", MT_LBP_GET);
8341 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET);
8342 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET);
8343 UFWORDX("STATE-LP!", MT_LP_SET);
8344 UFWORDX("STATE-LBP!", MT_LBP_SET);
8345 UFWORDX("STATE-DS@", MT_DSTACK_LOAD);
8346 UFWORDX("STATE-RS@", MT_RSTACK_LOAD);
8347 UFWORDX("STATE-LS@", MT_LSTACK_LOAD);
8348 UFWORDX("STATE-DS!", MT_DSTACK_STORE);
8349 UFWORDX("STATE-RS!", MT_RSTACK_STORE);
8350 UFWORDX("STATE-LS!", MT_LSTACK_STORE);
8351 UFWORDX("STATE-VSP@", MT_VSP_GET);
8352 UFWORDX("STATE-VSP!", MT_VSP_SET);
8353 UFWORDX("STATE-VSP-AT@", MT_VSP_LOAD);
8354 UFWORDX("STATE-VSP-AT!", MT_VSP_STORE);
8355 ufoVocSetOnlyDefs(ufoForthVocId);
8359 //==========================================================================
8361 // ufoInitTTYWords
8363 //==========================================================================
8364 UFO_DISABLE_INLINE void ufoInitTTYWords (void) {
8365 // create "TTY" vocabulary
8366 const uint32_t ttyVocId = ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED);
8367 ufoVocSetOnlyDefs(ttyVocId);
8368 UFWORDX("TTY?", TTY_TTYQ);
8369 UFWORDX("RAW?", TTY_RAWQ);
8370 UFWORDX("SIZE", TTY_SIZE);
8371 UFWORDX("SET-RAW", TTY_SET_RAW);
8372 UFWORDX("SET-COOKED", TTY_SET_COOKED);
8373 UFWORDX("RAW-EMIT", TTY_RAW_EMIT);
8374 UFWORDX("RAW-TYPE", TTY_RAW_TYPE);
8375 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH);
8376 UFWORDX("RAW-READCH", TTY_RAW_READCH);
8377 UFWORDX("RAW-READY?", TTY_RAW_READYQ);
8378 ufoVocSetOnlyDefs(ufoForthVocId);
8382 //==========================================================================
8384 // ufoInitFilesWords
8386 //==========================================================================
8387 UFO_DISABLE_INLINE void ufoInitFilesWords (void) {
8388 // create "FILES" vocabulary
8389 const uint32_t filesVocId = ufoCreateVoc("FILES", 0, UFW_FLAG_PROTECTED);
8390 ufoVocSetOnlyDefs(filesVocId);
8391 ufoDefineConstant("SEEK-SET", SEEK_SET);
8392 ufoDefineConstant("SEEK-CUR", SEEK_CUR);
8393 ufoDefineConstant("SEEK-END", SEEK_END);
8395 UFWORDX("OPEN-R/O", FILES_OPEN_RO);
8396 UFWORDX("OPEN-R/W", FILES_OPEN_RW);
8397 UFWORDX("CREATE", FILES_CREATE);
8398 UFWORDX("CLOSE", FILES_CLOSE);
8399 UFWORDX("TELL", FILES_TELL);
8400 UFWORDX("SEEK-EX", FILES_SEEK_EX);
8401 UFWORDX("SIZE", FILES_SIZE);
8402 UFWORDX("READ", FILES_READ);
8403 UFWORDX("READ-EXACT", FILES_READ_EXACT);
8404 UFWORDX("WRITE", FILES_WRITE);
8406 UFWORDX("UNLINK", FILES_UNLINK);
8408 UFWORDX("ERRNO", FILES_ERRNO);
8410 ufoInterpretLine(
8411 ": SEEK ( ofs handle -- success? ) "
8412 " SEEK-SET FORTH:SWAP SEEK-EX "
8413 ";");
8416 ufoInterpretLine(
8417 ": READ-EXACT ( addr count handle -- success? ) "
8418 " FORTH:OVER FORTH:>R ( save count ) "
8419 " READ FORTH:DUP FORTH:(0BRANCH) $files-read-exact-error "
8420 " FORTH:DROP ( drop TRUE ) FORTH:R@ = "
8421 "$files-read-exact-error: "
8422 " RDROP "
8423 ";");
8426 ufoVocSetOnlyDefs(ufoForthVocId);
8430 //==========================================================================
8432 // ufoInitVeryVeryHighWords
8434 //==========================================================================
8435 UFO_DISABLE_INLINE void ufoInitVeryVeryHighWords (void) {
8436 // interpret defer
8437 //ufoDefineDefer("INTERPRET", idumbCFA);
8439 ufoDefineEmitType();
8441 // ( addr count FALSE -- addr count FALSE / TRUE )
8442 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
8443 ufoDoneForth();
8444 // ( addr count FALSE -- addr count FALSE / TRUE )
8445 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
8446 ufoDoneForth();
8447 // ( -- ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
8448 ufoDefineSColonForth("(EXIT-EXTENDER)");
8449 ufoDoneForth();
8451 // EXIT ( -- )
8452 ufoInterpretLine("!: EXIT ( -- ) COMPILER:?COMP (EXIT-EXTENDER) COMPILE FORTH:(EXIT) ;");
8454 ufoDefineInterpret();
8456 //ufoDumpVocab(ufoCompilerVocId);
8458 ufoInterpretLine(
8459 ": RUN-INTERPRET-LOOP "
8460 "$run-interp-loop-again: "
8461 " RP0! INTERPRET (UFO-INTERPRET-FINISHED-ACTION) "
8462 " FORTH:(BRANCH) $run-interp-loop-again "
8463 ";");
8466 #define UFO_ADD_DO_CFA(cfx_) do { \
8467 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
8468 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
8469 ufoCFAsUsed += 1; \
8470 } while (0)
8473 //==========================================================================
8475 // ufoInitCommon
8477 //==========================================================================
8478 UFO_DISABLE_INLINE void ufoInitCommon (void) {
8479 ufoVSP = 0;
8480 ufoForthVocId = 0; ufoCompilerVocId = 0;
8482 ufoForthCFAs = calloc(UFO_MAX_NATIVE_CFAS, sizeof(ufoForthCFAs[0]));
8484 // allocate default TIB handle
8485 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
8486 //ufoDefTIB = tibh->ufoHandle;
8488 ufoForthCFAs[0] = NULL; ufoCFAsUsed = 1u;
8489 UFO_ADD_DO_CFA(Forth);
8490 UFO_ADD_DO_CFA(Variable);
8491 UFO_ADD_DO_CFA(Value);
8492 UFO_ADD_DO_CFA(Const);
8493 UFO_ADD_DO_CFA(Defer);
8494 UFO_ADD_DO_CFA(Voc);
8495 UFO_ADD_DO_CFA(Create);
8496 UFO_ADD_DO_CFA(UserVariable);
8498 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
8500 ufoInitBaseDict();
8502 // create "FORTH" vocabulary (it should be the first one)
8503 ufoForthVocId = ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED);
8504 ufoVocSetOnlyDefs(ufoForthVocId);
8506 // base low-level interpreter words
8507 ufoInitBasicWords();
8509 // more FORTH words
8510 ufoInitMoreWords();
8512 // some COMPILER words
8513 ufoInitBasicCompilerWords();
8515 // STRING vocabulary
8516 ufoInitStringWords();
8518 // DEBUG vocabulary
8519 ufoInitDebugWords();
8521 // MTASK vocabulary
8522 ufoInitMTWords();
8524 // HANDLE vocabulary
8525 ufoInitHandleWords();
8527 // TTY vocabulary
8528 ufoInitTTYWords();
8530 // FILES vocabulary
8531 ufoInitFilesWords();
8533 // some higher-level FORTH words (includes, etc.)
8534 ufoInitHigherWords();
8536 // very-very high-level FORTH words
8537 ufoInitVeryVeryHighWords();
8539 ufoFinalLabelCheck();
8541 #if 0
8542 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
8543 #endif
8545 ufoReset();
8548 #undef UFC
8551 // ////////////////////////////////////////////////////////////////////////// //
8552 // virtual machine executor
8556 //==========================================================================
8558 // ufoRunVM
8560 // address interpreter
8562 //==========================================================================
8563 static void ufoRunVMCFA (uint32_t cfa) {
8564 const uint32_t oldRPTop = ufoRPTop;
8565 ufoRPTop = ufoRP;
8566 #ifdef UFO_TRACE_VM_RUN
8567 fprintf(stderr, "**VM-INITIAL**: cfa=%u\n", cfa);
8568 UFCALL(DUMP_STACK);
8569 #endif
8570 ufoRPush(cfa);
8571 ufoVMRPopCFA = 1;
8572 ufoVMStop = 0;
8573 // VM execution loop
8574 do {
8575 if (ufoVMAbort) ufoFatal("user abort");
8576 if (ufoVMStop) { ufoRP = oldRPTop; break; }
8577 if (ufoCurrState == NULL) ufoFatal("execution state is lost");
8578 if (ufoVMRPopCFA == 0) {
8579 // check IP
8580 if (ufoIP == 0) ufoFatal("IP is NULL");
8581 if (ufoIP & UFO_ADDR_HANDLE_BIT) ufoFatal("IP is a handle");
8582 cfa = ufoImgGetU32(ufoIP); ufoIP += 4u;
8583 } else {
8584 cfa = ufoRPop(); ufoVMRPopCFA = 0;
8586 // check CFA sanity
8587 if (cfa == 0) ufoFatal("EXECUTE: NULL CFA");
8588 if (cfa & UFO_ADDR_HANDLE_BIT) ufoFatal("cannot execute handle");
8589 // get next word CFAIDX, and check it
8590 uint32_t cfaidx = ufoImgGetU32(cfa);
8591 if (cfaidx & UFO_ADDR_HANDLE_BIT) ufoFatal("cannot execute CFAIDX-handle");
8592 #ifdef UFO_TRACE_VM_RUN
8593 fprintf(stderr, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP - 4u, cfa, cfaidx);
8594 UFCALL(DUMP_STACK);
8595 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa));
8596 fprintf(stderr, "######################################\n");
8597 #endif
8598 if (cfaidx & UFO_ADDR_CFA_BIT) {
8599 cfaidx &= UFO_ADDR_CFA_MASK;
8600 if (cfaidx >= ufoCFAsUsed || ufoForthCFAs[cfaidx] == NULL) {
8601 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
8602 cfaidx, ufoCFAsUsed, ufoIP - 4u);
8604 #ifdef UFO_TRACE_VM_RUN
8605 fprintf(stderr, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx,
8606 (ufoDoForthCFA & UFO_ADDR_CFA_MASK));
8607 #endif
8608 ufoForthCFAs[cfaidx](UFO_CFA_TO_PFA(cfa));
8609 } else {
8610 // if CFA points somewhere inside a dict, this is "DOES>" word
8611 // IP points to PFA we need to push
8612 // CFA points to Forth word we need to jump to
8613 #ifdef UFO_TRACE_VM_DOER
8614 fprintf(stderr, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP, cfa, cfaidx);
8615 UFCALL(UFO_BACKTRACE);
8616 #endif
8617 ufoPush(UFO_CFA_TO_PFA(cfa)); // push PFA
8618 ufoRPush(ufoIP); // push IP
8619 ufoIP = cfaidx; // fix IP
8621 // that's all we need to activate the debugger
8622 if (ufoSingleStep) {
8623 ufoSingleStep -= 1;
8624 if (ufoSingleStep == 0 && ufoDebuggerState != NULL) {
8625 if (ufoCurrState == ufoDebuggerState) ufoFatal("debugger cannot debug itself");
8626 UfoState *ost = ufoCurrState;
8627 ufoSwitchToState(ufoDebuggerState); // always use API call for this!
8628 ufoPush(-2);
8629 ufoPush(ost->id);
8632 } while (ufoRP != oldRPTop);
8633 //ufoVMStop = 0;
8637 // ////////////////////////////////////////////////////////////////////////// //
8638 // high-level API
8641 //==========================================================================
8643 // ufoRegisterWord
8645 // register new word
8647 //==========================================================================
8648 uint32_t ufoRegisterWord (const char *wname, ufoNativeCFA cfa, uint32_t flags) {
8649 ufo_assert(cfa != NULL);
8650 ufo_assert(wname != NULL && wname[0] != 0);
8651 uint32_t cfaidx = ufoCFAsUsed;
8652 if (cfaidx >= UFO_MAX_NATIVE_CFAS) ufoFatal("too many native words");
8653 ufoForthCFAs[cfaidx] = cfa;
8654 ufoCFAsUsed += 1;
8655 //ufoDefineNative(wname, xcfa, 0);
8656 cfaidx |= UFO_ADDR_CFA_BIT;
8657 flags &= 0xffffff00u;
8658 ufoCreateWordHeader(wname, flags);
8659 const uint32_t res = UFO_GET_DP();
8660 ufoImgEmitU32(cfaidx);
8661 return res;
8665 //==========================================================================
8667 // ufoRegisterDataWord
8669 //==========================================================================
8670 static uint32_t ufoRegisterDataWord (const char *wname, uint32_t cfaidx, uint32_t value,
8671 uint32_t flags)
8673 ufo_assert(wname != NULL && wname[0] != 0);
8674 flags &= 0xffffff00u;
8675 ufoCreateWordHeader(wname, flags);
8676 ufoImgEmitU32(cfaidx);
8677 const uint32_t res = UFO_GET_DP();
8678 ufoImgEmitU32(value);
8679 return res;
8683 //==========================================================================
8685 // ufoRegisterConstant
8687 //==========================================================================
8688 void ufoRegisterConstant (const char *wname, uint32_t value, uint32_t flags) {
8689 (void)ufoRegisterDataWord(wname, ufoDoConstCFA, value, flags);
8693 //==========================================================================
8695 // ufoRegisterVariable
8697 //==========================================================================
8698 uint32_t ufoRegisterVariable (const char *wname, uint32_t value, uint32_t flags) {
8699 return ufoRegisterDataWord(wname, ufoDoVariableCFA, value, flags);
8703 //==========================================================================
8705 // ufoRegisterValue
8707 //==========================================================================
8708 uint32_t ufoRegisterValue (const char *wname, uint32_t value, uint32_t flags) {
8709 return ufoRegisterDataWord(wname, ufoDoValueCFA, value, flags);
8713 //==========================================================================
8715 // ufoRegisterDefer
8717 //==========================================================================
8718 uint32_t ufoRegisterDefer (const char *wname, uint32_t value, uint32_t flags) {
8719 return ufoRegisterDataWord(wname, ufoDoDeferCFA, value, flags);
8723 //==========================================================================
8725 // ufoFindWordInVocabulary
8727 // check if we have the corresponding word.
8728 // return CFA suitable for executing, or 0.
8730 //==========================================================================
8731 uint32_t ufoFindWordInVocabulary (const char *wname, uint32_t vocid) {
8732 if (wname == NULL || wname[0] == 0) return 0;
8733 size_t wlen = strlen(wname);
8734 if (wlen >= UFO_MAX_WORD_LENGTH) return 0;
8735 return ufoFindWordInVocAndParents(wname, (uint32_t)wlen, 0, vocid, 0);
8739 //==========================================================================
8741 // ufoGetIP
8743 //==========================================================================
8744 uint32_t ufoGetIP (void) {
8745 return ufoIP;
8749 //==========================================================================
8751 // ufoSetIP
8753 //==========================================================================
8754 void ufoSetIP (uint32_t newip) {
8755 ufoIP = newip;
8759 //==========================================================================
8761 // ufoIsExecuting
8763 //==========================================================================
8764 int ufoIsExecuting (void) {
8765 return (ufoImgGetU32(ufoAddrSTATE) == 0);
8769 //==========================================================================
8771 // ufoIsCompiling
8773 //==========================================================================
8774 int ufoIsCompiling (void) {
8775 return (ufoImgGetU32(ufoAddrSTATE) != 0);
8779 //==========================================================================
8781 // ufoSetExecuting
8783 //==========================================================================
8784 void ufoSetExecuting (void) {
8785 ufoImgPutU32(ufoAddrSTATE, 0);
8789 //==========================================================================
8791 // ufoSetCompiling
8793 //==========================================================================
8794 void ufoSetCompiling (void) {
8795 ufoImgPutU32(ufoAddrSTATE, 1);
8799 //==========================================================================
8801 // ufoGetHere
8803 //==========================================================================
8804 uint32_t ufoGetHere () {
8805 return UFO_GET_DP();
8809 //==========================================================================
8811 // ufoGetPad
8813 //==========================================================================
8814 uint32_t ufoGetPad () {
8815 UFCALL(PAD);
8816 return ufoPop();
8820 //==========================================================================
8822 // ufoTIBPeekCh
8824 //==========================================================================
8825 uint8_t ufoTIBPeekCh (uint32_t ofs) {
8826 return ufoTibPeekChOfs(ofs);
8830 //==========================================================================
8832 // ufoTIBGetCh
8834 //==========================================================================
8835 uint8_t ufoTIBGetCh (void) {
8836 return ufoTibGetCh();
8840 //==========================================================================
8842 // ufoTIBSkipCh
8844 //==========================================================================
8845 void ufoTIBSkipCh (void) {
8846 ufoTibSkipCh();
8850 //==========================================================================
8852 // ufoTIBSRefill
8854 // returns 0 on EOF
8856 //==========================================================================
8857 int ufoTIBSRefill (int allowCrossIncludes) {
8858 return ufoLoadNextLine(allowCrossIncludes);
8862 //==========================================================================
8864 // ufoPeekData
8866 //==========================================================================
8867 uint32_t ufoPeekData (void) {
8868 return ufoPeek();
8872 //==========================================================================
8874 // ufoPopData
8876 //==========================================================================
8877 uint32_t ufoPopData (void) {
8878 return ufoPop();
8882 //==========================================================================
8884 // ufoPushData
8886 //==========================================================================
8887 void ufoPushData (uint32_t value) {
8888 return ufoPush(value);
8892 //==========================================================================
8894 // ufoPushBoolData
8896 //==========================================================================
8897 void ufoPushBoolData (int val) {
8898 ufoPushBool(val);
8902 //==========================================================================
8904 // ufoPeekRet
8906 //==========================================================================
8907 uint32_t ufoPeekRet (void) {
8908 return ufoRPeek();
8912 //==========================================================================
8914 // ufoPopRet
8916 //==========================================================================
8917 uint32_t ufoPopRet (void) {
8918 return ufoRPop();
8922 //==========================================================================
8924 // ufoPushRet
8926 //==========================================================================
8927 void ufoPushRet (uint32_t value) {
8928 return ufoRPush(value);
8932 //==========================================================================
8934 // ufoPushBoolRet
8936 //==========================================================================
8937 void ufoPushBoolRet (int val) {
8938 ufoRPush(val ? ufoTrueValue : 0);
8942 //==========================================================================
8944 // ufoPeekByte
8946 //==========================================================================
8947 uint8_t ufoPeekByte (uint32_t addr) {
8948 return ufoImgGetU8Ext(addr);
8952 //==========================================================================
8954 // ufoPeekWord
8956 //==========================================================================
8957 uint16_t ufoPeekWord (uint32_t addr) {
8958 ufoPush(addr);
8959 UFCALL(WPEEK);
8960 return ufoPop();
8964 //==========================================================================
8966 // ufoPeekCell
8968 //==========================================================================
8969 uint32_t ufoPeekCell (uint32_t addr) {
8970 ufoPush(addr);
8971 UFCALL(PEEK);
8972 return ufoPop();
8976 //==========================================================================
8978 // ufoPokeByte
8980 //==========================================================================
8981 void ufoPokeByte (uint32_t addr, uint32_t value) {
8982 ufoImgPutU8(addr, value);
8986 //==========================================================================
8988 // ufoPokeWord
8990 //==========================================================================
8991 void ufoPokeWord (uint32_t addr, uint32_t value) {
8992 ufoPush(value);
8993 ufoPush(addr);
8994 UFCALL(WPOKE);
8998 //==========================================================================
9000 // ufoPokeCell
9002 //==========================================================================
9003 void ufoPokeCell (uint32_t addr, uint32_t value) {
9004 ufoPush(value);
9005 ufoPush(addr);
9006 UFCALL(POKE);
9010 //==========================================================================
9012 // ufoGetPAD
9014 //==========================================================================
9015 uint32_t ufoGetPAD (void) {
9016 return UFO_PAD_ADDR;
9020 //==========================================================================
9022 // ufoEmitByte
9024 //==========================================================================
9025 void ufoEmitByte (uint32_t value) {
9026 ufoImgEmitU8(value);
9030 //==========================================================================
9032 // ufoEmitWord
9034 //==========================================================================
9035 void ufoEmitWord (uint32_t value) {
9036 ufoImgEmitU8(value & 0xff);
9037 ufoImgEmitU8((value >> 8) & 0xff);
9041 //==========================================================================
9043 // ufoEmitCell
9045 //==========================================================================
9046 void ufoEmitCell (uint32_t value) {
9047 ufoImgEmitU32(value);
9051 //==========================================================================
9053 // ufoIsInited
9055 //==========================================================================
9056 int ufoIsInited (void) {
9057 return (ufoMode != UFO_MODE_NONE);
9061 static void (*ufoUserPostInitCB) (void);
9064 //==========================================================================
9066 // ufoSetUserPostInit
9068 // called after main initialisation
9070 //==========================================================================
9071 void ufoSetUserPostInit (void (*cb) (void)) {
9072 ufoUserPostInitCB = cb;
9076 //==========================================================================
9078 // ufoInit
9080 //==========================================================================
9081 void ufoInit (void) {
9082 if (ufoMode != UFO_MODE_NONE) return;
9083 ufoMode = UFO_MODE_NATIVE;
9085 ufoInFileLine = 0;
9086 ufoInFileName = NULL; ufoInFileNameLen = 0; ufoInFileNameHash = 0;
9087 ufoInFile = NULL;
9088 ufoLastIncPath = NULL; ufoLastSysIncPath = NULL;
9090 for (uint32_t f = 0; f < UFO_MAX_STATES; f += 1u) ufoStateMap[f] = NULL;
9091 memset(ufoStateUsedBitmap, 0, sizeof(ufoStateUsedBitmap));
9093 ufoCurrState = ufoNewState();
9094 strcpy(ufoCurrState->name, "MAIN");
9095 ufoInitStateUserVars(ufoCurrState, 0);
9096 ufoImgPutU32(ufoAddrDefTIB, 0); // create TIB handle
9097 ufoImgPutU32(ufoAddrTIBx, 0); // create TIB handle
9099 ufoYieldedState = NULL;
9100 ufoDebuggerState = NULL;
9101 ufoSingleStep = 0;
9103 #ifdef UFO_DEBUG_STARTUP_TIMES
9104 uint32_t stt = ufo_get_msecs();
9105 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
9106 #endif
9107 ufoInitCommon();
9108 #ifdef UFO_DEBUG_STARTUP_TIMES
9109 uint32_t ett = ufo_get_msecs();
9110 fprintf(stderr, "UrForth init time: %u msecs\n", (unsigned)(ett - stt));
9111 #endif
9113 ufoReset();
9115 if (ufoUserPostInitCB) {
9116 ufoUserPostInitCB();
9117 ufoReset();
9120 // load ufo modules
9121 char *ufmname = ufoCreateIncludeName("init", 1, NULL);
9122 #ifdef WIN32
9123 FILE *ufl = fopen(ufmname, "rb");
9124 #else
9125 FILE *ufl = fopen(ufmname, "r");
9126 #endif
9127 if (ufl) {
9128 ufoPushInFile();
9129 ufoSetInFileNameReuse(ufmname);
9130 ufoInFile = ufl;
9131 ufoFileId = ufoLastUsedFileId;
9132 setLastIncPath(ufoInFileName, 1);
9133 } else {
9134 free(ufmname);
9135 ufoFatal("cannot load init code");
9138 if (ufoInFile != NULL) {
9139 ufoRunInterpretLoop();
9144 //==========================================================================
9146 // ufoFinishVM
9148 //==========================================================================
9149 void ufoFinishVM (void) {
9150 ufoVMStop = 1;
9154 //==========================================================================
9156 // ufoWasVMFinished
9158 // check if VM was exited due to `ufoFinishVM()`
9160 //==========================================================================
9161 int ufoWasVMFinished (void) {
9162 return (ufoVMStop != 0);
9166 //==========================================================================
9168 // ufoCallParseIntr
9170 // ( -- addr count TRUE / FALSE )
9171 // does base TIB parsing; never copies anything.
9172 // as our reader is line-based, returns FALSE on EOL.
9173 // EOL is detected after skipping leading delimiters.
9174 // passing -1 as delimiter skips the whole line, and always returns FALSE.
9175 // trailing delimiter is always skipped.
9176 // result is on the data stack.
9178 //==========================================================================
9179 void ufoCallParseIntr (uint32_t delim, int skipLeading) {
9180 ufoPush(delim); ufoPushBool(skipLeading);
9181 UFCALL(PAR_PARSE);
9184 //==========================================================================
9186 // ufoCallParseName
9188 // ( -- addr count )
9189 // parse with leading blanks skipping. doesn't copy anything.
9190 // return empty string on EOL.
9192 //==========================================================================
9193 void ufoCallParseName (void) {
9194 UFCALL(PARSE_NAME);
9198 //==========================================================================
9200 // ufoCallParse
9202 // ( -- addr count TRUE / FALSE )
9203 // parse without skipping delimiters; never copies anything.
9204 // as our reader is line-based, returns FALSE on EOL.
9205 // passing 0 as delimiter skips the whole line, and always returns FALSE.
9206 // trailing delimiter is always skipped.
9208 //==========================================================================
9209 void ufoCallParse (uint32_t delim) {
9210 ufoPush(delim);
9211 UFCALL(PARSE);
9215 //==========================================================================
9217 // ufoCallParseSkipBlanks
9219 //==========================================================================
9220 void ufoCallParseSkipBlanks (void) {
9221 UFCALL(PARSE_SKIP_BLANKS);
9225 //==========================================================================
9227 // ufoCallParseSkipComments
9229 //==========================================================================
9230 void ufoCallParseSkipComments (void) {
9231 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS);
9235 //==========================================================================
9237 // ufoCallParseSkipLineComments
9239 //==========================================================================
9240 void ufoCallParseSkipLineComments (void) {
9241 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS);
9245 //==========================================================================
9247 // ufoCallParseSkipLine
9249 // to the end of line; doesn't refill
9251 //==========================================================================
9252 void ufoCallParseSkipLine (void) {
9253 UFCALL(PARSE_SKIP_LINE);
9257 //==========================================================================
9259 // ufoCallBasedNumber
9261 // convert number from addrl+1
9262 // returns address of the first inconvertible char
9263 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
9265 //==========================================================================
9266 void ufoCallBasedNumber (uint32_t addr, uint32_t count, int allowSign, int base) {
9267 ufoPush(addr); ufoPush(count); ufoPushBool(allowSign);
9268 if (base < 0) ufoPush(0); else ufoPush((uint32_t)base);
9269 UFCALL(PAR_BASED_NUMBER);
9273 //==========================================================================
9275 // ufoRunWord
9277 //==========================================================================
9278 void ufoRunWord (uint32_t cfa) {
9279 if (cfa != 0) {
9280 if (ufoMode == UFO_MODE_NONE) ufoFatal("UrForth is not properly inited");
9281 if (ufoInRunWord) ufoFatal("`ufoRunWord` cannot be called recursively");
9282 ufoMode = UFO_MODE_NATIVE;
9283 ufoInRunWord = 1;
9284 ufoRunVMCFA(cfa);
9285 ufoInRunWord = 0;
9290 //==========================================================================
9292 // ufoRunMacroWord
9294 //==========================================================================
9295 void ufoRunMacroWord (uint32_t cfa) {
9296 if (cfa != 0) {
9297 if (ufoMode == UFO_MODE_NONE) ufoFatal("UrForth is not properly inited");
9298 if (ufoInRunWord) ufoFatal("`ufoRunWord` cannot be called recursively");
9299 ufoMode = UFO_MODE_MACRO;
9300 const uint32_t oisp = ufoFileStackPos;
9301 ufoPushInFile();
9302 ufoFileId = 0;
9303 (void)ufoLoadNextUserLine();
9304 ufoInRunWord = 1;
9305 ufoRunVMCFA(cfa);
9306 ufoInRunWord = 0;
9307 ufoPopInFile();
9308 ufo_assert(ufoFileStackPos == oisp); // sanity check
9313 //==========================================================================
9315 // ufoIsInMacroMode
9317 // check if we are currently in "MACRO" mode.
9318 // should be called from registered words.
9320 //==========================================================================
9321 int ufoIsInMacroMode (void) {
9322 return (ufoMode == UFO_MODE_MACRO);
9326 //==========================================================================
9328 // ufoRunInterpretLoop
9330 // run default interpret loop.
9332 //==========================================================================
9333 void ufoRunInterpretLoop (void) {
9334 if (ufoMode == UFO_MODE_NONE) {
9335 ufoInit();
9337 const uint32_t cfa = ufoFindWord("RUN-INTERPRET-LOOP");
9338 if (cfa == 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
9339 ufoReset();
9340 ufoMode = UFO_MODE_NATIVE;
9341 ufoInRunWord = 1;
9342 ufoRunVMCFA(cfa);
9343 ufoInRunWord = 0;
9344 while (ufoFileStackPos != 0) ufoPopInFile();
9348 //==========================================================================
9350 // ufoRunFile
9352 //==========================================================================
9353 void ufoRunFile (const char *fname) {
9354 if (ufoMode == UFO_MODE_NONE) {
9355 ufoInit();
9357 if (ufoInRunWord) ufoFatal("`ufoRunFile` cannot be called recursively");
9358 ufoMode = UFO_MODE_NATIVE;
9360 ufoReset();
9361 char *ufmname = ufoCreateIncludeName(fname, 0, ".");
9362 #ifdef WIN32
9363 FILE *ufl = fopen(ufmname, "rb");
9364 #else
9365 FILE *ufl = fopen(ufmname, "r");
9366 #endif
9367 if (ufl) {
9368 ufoPushInFile();
9369 ufoSetInFileNameReuse(ufmname);
9370 ufoInFile = ufl;
9371 ufoFileId = ufoLastUsedFileId;
9372 setLastIncPath(ufoInFileName, 0);
9373 } else {
9374 free(ufmname);
9375 ufoFatal("cannot load source file '%s'", fname);
9377 ufoRunInterpretLoop();