1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
12 #include <sys/types.h>
16 //#define UFO_UPPERCASE_DICT_WORDS
19 //#define UFO_DEBUG_FATAL_ABORT
20 //#define UFO_DEBUG_PARSE
21 //#define UFO_DEBUG_INLCUDE
24 #define UFO_FORCE_INLINE static inline __attribute__((always_inline))
25 #define UFO_INLINE static inline
28 #define UFO_QPAIRS_BEGIN (1)
29 #define UFO_QPAIRS_IF (2)
30 #define UFO_QPAIRS_DO (3)
31 #define UFO_QPAIRS_CASE (4)
32 #define UFO_QPAIRS_OF (5)
33 #define UFO_QPAIRS_OTHER (6)
34 #define UFO_QPAIRS_WHILE (7)
35 #define UFO_QPAIRS_CBLOCK (666)
37 // should not be bigger than this!
38 #define UFO_MAX_WORD_LENGTH (127)
41 static const char *ufo_assert_failure (const char *cond
, const char *fname
, int fline
,
44 for (const char *t
= fname
; *t
; ++t
) {
46 if (*t
== '/' || *t
== '\\') fname
= t
+1;
48 if (*t
== '/') fname
= t
+1;
52 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
57 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
60 //==========================================================================
64 //==========================================================================
65 static uint32_t joaatHashBufCI (const void *buf
, size_t len
) {
66 uint32_t hash
= 0x29a;
67 const uint8_t *s
= (const uint8_t *)buf
;
69 //hash += (uint8_t)locase1251(*s++);
70 hash
+= (*s
++)|0x20; // this converts ASCII capitals to locase (and destroys other, but who cares)
82 //==========================================================================
86 //==========================================================================
87 UFO_FORCE_INLINE
char toUpper (char ch
) {
88 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
92 //==========================================================================
96 //==========================================================================
97 static int strEquCI (const char *s0
, const char *s1
) {
99 while (res
&& *s0
&& *s1
) {
100 char c0
= *s0
++; if (c0
>= 'A' && c0
<= 'Z') c0
= c0
- 'A' + 'a';
101 char c1
= *s1
++; if (c1
>= 'A' && c1
<= 'Z') c1
= c1
- 'A' + 'a';
104 return (res
&& s0
[0] == 0 && s1
[0] == 0);
108 //==========================================================================
112 //==========================================================================
113 static int digitInBase (char ch
, int base
) {
115 case '0' ... '9': ch
= ch
- '0'; break;
116 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
117 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
118 default: base
= -1; break;
120 return (ch
>= 0 && ch
< base
? ch
: -1);
124 // ////////////////////////////////////////////////////////////////////////// //
125 #define UFW_FLAG_IMMEDIATE (1u<<0)
126 #define UFW_FLAG_PROTECTED (1u<<1)
127 #define UFW_FLAG_HIDDEN (1u<<2)
128 #define UFW_FLAG_VOC_HIDDEN (1u<<3)
130 #define UFW_IS_IMM(fw_) (((fw_)->flags&UFW_FLAG_IMMEDIATE) != 0)
131 #define UFW_IS_PROT(fw_) (((fw_)->flags&UFW_FLAG_PROTECTED) != 0)
132 #define UFW_IS_HID(fw_) (((fw_)->flags&UFW_FLAG_HIDDEN) != 0)
133 #define UFW_IS_VOC_HID(fw_) (((fw_)->flags&UFW_FLAG_VOC_HIDDEN) != 0)
135 #define UFW_VOCAB_OFS_MYCFA (0)
136 #define UFW_VOCAB_OFS_PARENT (1)
137 #define UFW_VOCAB_OFS_VOCLINK (2)
140 typedef struct UForthWord_t UForthWord
;
141 struct UForthWord_t
{
144 UForthWord
*prevAll
; // in global list
145 UForthWord
*prevVoc
; // in vocabulary
146 void (*cfa
) (UForthWord
*self
); // `self` may be NULL if called from the internal code
147 uint32_t cfaidx
; // in `ufoForthCFAs`
148 uint32_t pfastart
; // pointer to image
149 uint32_t pfaend
; // set in `;`
150 uint32_t pfa
; // pointer to image
151 uint32_t flags
; // see `UFW_FLAG_xxx`
152 // hash and bucket link
155 // parent vocabulary link (for vocabularies only)
157 UForthWord
**buckets
; // vocabulary hash table
160 #define UFO_DICT_HASH_BUCKETS (64u)
161 static UForthWord
*ufoForthDict
= NULL
;
162 static UForthWord
*ufoColonWord
= NULL
;
164 static jmp_buf ufoInlineQuitJP
;
166 #define UFO_MAX_WORDS (65536u)
167 static UForthWord
**ufoForthCFAs
= NULL
;
168 static unsigned ufoCFAsUsed
= 0;
170 #define UFO_ZX_ADDR_BIT (1u<<30)
171 #define UFO_ZX_ADDR_MASK (0xffffU)
173 #define UFO_RS_CFA_BIT (1u<<31)
174 #define UFO_RS_CFA_MASK ((1u<<31)-1u)
176 #define UFO_ENSURE_NATIVE_ADDR(adr_) do { \
177 const uint32_t aa = (uint32_t)(adr_); \
178 if (aa & UFO_ZX_ADDR_BIT) ufoFatal("unexpected ZX address"); \
179 if (aa & UFO_RS_CFA_BIT) ufoFatal("unexpected CFA address"); \
182 #define UFO_ENSURE_NATIVE_CFA(adr_) ({ \
183 const uint32_t aa = (uint32_t)(adr_); \
184 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
185 if ((aa&UFO_RS_CFA_MASK) >= ufoCFAsUsed || ufoForthCFAs[(aa&UFO_RS_CFA_MASK)] == NULL) ufoFatal("invalid CFA address"); \
189 #define UFO_GET_NATIVE_CFA(adr_) ({ \
190 uint32_t aa = (uint32_t)(adr_); \
191 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
192 aa &= UFO_RS_CFA_MASK; \
193 if (aa >= ufoCFAsUsed || ufoForthCFAs[aa] == NULL) ufoFatal("invalid CFA address"); \
197 #define FW_GET_CFAIDX(fw_) ((fw_)->cfaidx & UFO_RS_CFA_MASK)
198 #define FW_SET_CFAIDX(fw_,ci_) ((fw_)->cfaidx = (((ci_) & UFO_RS_CFA_MASK) | UFO_RS_CFA_BIT))
200 static uint32_t *ufoImage
= NULL
;
201 static uint32_t ufoImageSize
= 0;
202 static uint32_t ufoImageUsed
= 0;
204 static uint32_t ufoIP
= 0; // in image
205 static uint32_t ufoSP
= 0; // points AFTER the last value pushed
206 static uint32_t ufoRP
= 0; // points AFTER the last value pushed
207 static uint32_t ufoRPTop
= 0; // stop when RP is this, and we're doing EXIT
209 static uint32_t ufoTrueValue
= ~0u;
211 // the compiler works in two modes
212 // first mode is "native"
213 // only forth variables are allowed, and they're leaving ZX addresses
214 // second mode is "zx"
215 // in this mode, various creation words will create things in ZX memory.
216 // note that in interpret mode it is still possible to perform various
217 // native calculations, and call native words.
218 // but calling native word while compiling ZX code is possible only if it
219 // is an immediate one.
222 UFO_MODE_NATIVE
= 0, // executing forth code
223 UFO_MODE_MACRO
= 1, // executing forth asm macro
225 static uint32_t ufoMode
= UFO_MODE_NONE
;
227 // hack for `IMMEDIATE`
229 // only one of those can be set! (invariant)
230 static UForthWord
*ufoLastDefinedNativeWord
= NULL
;
232 #define UFO_DSTACK_SIZE (8192)
233 #define UFO_RSTACK_SIZE (8192)
234 static uint32_t *ufoDStack
= NULL
;
235 static uint32_t *ufoRStack
= NULL
;
238 typedef struct UForthLocRecord_t
{
239 char name
[128]; // local name
240 uint32_t lidx
; // offset from the current local ptr
241 struct UForthLocRecord_t
*next
;
244 #define UFO_LSTACK_SIZE (8192)
245 static uint32_t *ufoLStack
= NULL
;
246 static uint32_t ufoLP
, ufoLBP
; // bottom, base; nice names, yeah
247 // used in the compiler
248 static UForthLocRecord
*ufoLocals
= NULL
;
250 // dynamically allocated text input buffer
251 // always ends with zero (this is word name too)
252 // first 512 cells of image is TIB
253 static uint32_t ufoTIBAreaSize
= 512;
255 static uint32_t ufoAddrTIB
= 0; // TIB; 0 means "in TIB area", otherwise in the dictionary
256 static uint32_t ufoAddrIN
= 0; // >IN
258 static uint32_t ufoAddrContext
= 0; // CONTEXT
259 static uint32_t ufoAddrCurrent
= 0; // CURRENT
260 static uint32_t ufoDefaultVocFlags
= 0;
261 static uint32_t ufoLastVoc
= 0;
263 static uint32_t ufoBASEaddr
; // address of "BASE" variable
264 static uint32_t ufoSTATEaddr
; // address of "STATE" variable
265 static uint32_t ufoStopVM
;
266 static int ufoInColon
; // should be signed
268 #define UFO_PAD_OFFSET (2048u)
269 #define UFO_PAD1_OFFSET (4096u)
271 #define UFO_MAX_NESTED_INCLUDES (32)
278 uint32_t savedTIBSize
;
281 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
282 static uint32_t ufoFileStackPos
; // after the last used item
284 static FILE *ufoInFile
= NULL
;
285 static char *ufoInFileName
= NULL
;
286 static char *ufoLastIncPath
= NULL
;
287 static int ufoInFileLine
= 0;
288 static int ufoCondStLine
= -1;
290 static int ufoLastEmitWasCR
= 1;
291 static uint32_t ufoCSP
= 0;
292 static int ufoInCondIf
= 0;
294 #define UFO_VOCSTACK_SIZE (16u)
295 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
296 static uint32_t ufoVSP
;
297 static uint32_t ufoForthVocCFA
;
298 static uint32_t ufoCompSuppVocCFA
;
299 static uint32_t ufoMacroVocCFA
;
301 static char ufoCurrFileLine
[520];
302 // used to extract strings from the image
303 static char ufoTempCharBuf
[1024];
306 // ////////////////////////////////////////////////////////////////////////// //
308 static void ufoDbgDeinit (void);
310 static void ufoClearCondDefines (void);
311 static void ufoRunVM (void);
313 static int ufoParseConditionExpr (int doskip
);
316 //==========================================================================
320 //==========================================================================
321 static void setLastIncPath (const char *fname
) {
322 if (fname
== NULL
|| fname
[0] == 0) {
323 if (ufoLastIncPath
) free(ufoLastIncPath
);
324 ufoLastIncPath
= strdup(".");
326 if (ufoLastIncPath
) free(ufoLastIncPath
);
327 ufoLastIncPath
= strdup(fname
);
328 char *lslash
= ufoLastIncPath
;
329 char *cpos
= ufoLastIncPath
;
332 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
334 if (*cpos
== '/') lslash
= cpos
;
343 // ////////////////////////////////////////////////////////////////////////// //
344 UFO_FORCE_INLINE
uint32_t ufoPadAddr (void) {
345 return (ufoImageUsed
+ UFO_PAD_OFFSET
+ 1023u) / 1024u * 1024u;
349 static void ufoDoForth (UForthWord
*self
);
350 static void ufoDoVariable (UForthWord
*self
);
351 static void ufoDoValue (UForthWord
*self
);
352 static void ufoDoConst (UForthWord
*self
);
353 static void ufoDoDefer (UForthWord
*self
);
354 static void ufoDoVoc (UForthWord
*self
);
357 //==========================================================================
361 //==========================================================================
362 static void ufoErrorWriteFile (FILE *fo
) {
364 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
366 fprintf(fo
, "UFO ERROR somewhere in time: ");
371 //==========================================================================
375 //==========================================================================
376 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
377 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
379 ufoErrorWriteFile(stderr
);
380 vfprintf(stderr
, fmt
, ap
);
387 //==========================================================================
391 //==========================================================================
392 static void ufoStackTrace (void) {
393 // dump data stack (top 16)
394 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
395 uint32_t xsp
= ufoSP
;
396 if (xsp
> 16) xsp
= 16;
397 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
398 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
399 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
401 //if (ufoSP != 0) fputc('\n', stderr);
403 // dump return stack (top 32)
404 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
406 uint32_t rscount
= 0;
407 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
408 while (rscount
!= 32 && rp
!= 0) {
410 uint32_t cfa
= ufoRStack
[rp
];
411 if (cfa
& UFO_RS_CFA_BIT
) {
412 cfa
&= UFO_RS_CFA_MASK
;
413 if (cfa
< ufoCFAsUsed
&& ufoForthCFAs
[cfa
] != NULL
) {
414 UForthWord
*fw
= ufoForthCFAs
[cfa
];
415 fprintf(stderr
, " %2u: %s\n", rscount
, fw
->name
);
417 fprintf(stderr
, " %2u: wutafuck?\n", rscount
);
427 //==========================================================================
431 //==========================================================================
432 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
433 void ufoFatal (const char *fmt
, ...) {
436 ufoErrorMsgV(fmt
, ap
);
438 #ifdef UFO_DEBUG_FATAL_ABORT
445 //==========================================================================
449 //==========================================================================
450 static void ufoWipeLocRecords (void) {
451 while (ufoLocals
!= NULL
) {
452 UForthLocRecord
*r
= ufoLocals
;
453 ufoLocals
= ufoLocals
->next
;
459 //==========================================================================
463 // return !0 for duplicate
465 //==========================================================================
466 static void ufoNewLocal (const char *name
) {
469 if (name
== NULL
|| name
[0] == 0) ufoFatal("empty local name");
470 const size_t nlen
= strlen(name
);
471 if (nlen
> 127) ufoFatal("local name too long");
472 for (size_t f
= 0; f
< nlen
; f
+= 1) {
474 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
475 //if (ch == ':' || ch == '!') ufoFatal("invalid local name '%s'", name);
480 UForthLocRecord
*r
= ufoLocals
;
481 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
483 if (r
!= NULL
) ufoFatal("duplocate local '%s'", name
);
485 r
= calloc(1, sizeof(*r
));
486 strcpy(r
->name
, buf
);
487 if (ufoLocals
== 0) r
->lidx
= 1; else r
->lidx
= ufoLocals
->lidx
+ 1;
488 r
->next
= ufoLocals
; ufoLocals
= r
;
492 //==========================================================================
496 //==========================================================================
497 static UForthLocRecord
*ufoFindLocal (const char *name
, int *wantStore
) {
500 if (wantStore
) *wantStore
= 0;
501 if (name
== NULL
|| name
[0] != ':' || name
[1] == 0) return NULL
;
502 name
+= 1; // skip colon
503 size_t nlen
= strlen(name
);
504 if (nlen
!= 0 && name
[nlen
- 1] == '!') {
505 if (wantStore
) *wantStore
= 1;
507 if (nlen
== 0) return NULL
;
509 if (nlen
> 127) return NULL
;
510 for (size_t f
= 0; f
< nlen
; f
+= 1) {
512 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
517 UForthLocRecord
*r
= ufoLocals
;
518 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
524 //==========================================================================
528 //==========================================================================
529 static void ufoImgEnsureSize (uint32_t addr
) {
530 UFO_ENSURE_NATIVE_ADDR(addr
);
531 if (addr
>= ufoImageSize
) {
532 // 256MB should be enough for everyone!
533 // one cell is 4 bytes, so max address is 64MB
534 if (addr
>= 0x04000000U
) {
535 ufoFatal("UFO image grown too big (addr=0%08XH)", addr
);
537 const uint32_t osz
= ufoImageSize
;
538 // grow by 4MB steps (16 real MBs)
539 uint32_t nsz
= (addr
|0x003fffffU
) + 1U;
540 uint32_t *nimg
= realloc(ufoImage
, nsz
* sizeof(ufoImage
[0]));
542 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
543 ufoImageSize
/ 1024u / 1024u,
544 nsz
/ 1024u / 1024u);
548 memset(ufoImage
+ osz
, 0, (nsz
- osz
) * sizeof(ufoImage
[0]));
553 //==========================================================================
557 //==========================================================================
558 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, uint32_t value
) {
559 UFO_ENSURE_NATIVE_ADDR(addr
);
560 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
561 ufoImage
[addr
] = value
&0xffU
;
565 //==========================================================================
569 //==========================================================================
570 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, uint32_t value
) {
571 UFO_ENSURE_NATIVE_ADDR(addr
);
572 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
573 ufoImage
[addr
] = value
;
577 //==========================================================================
581 //==========================================================================
582 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
583 ufoImgPutU8(ufoImageUsed
, value
);
588 //==========================================================================
592 //==========================================================================
593 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
594 ufoImgPutU32(ufoImageUsed
, value
);
599 //==========================================================================
603 //==========================================================================
604 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
605 UFO_ENSURE_NATIVE_ADDR(addr
);
606 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
607 return ufoImage
[addr
]&0xffU
;
611 //==========================================================================
615 //==========================================================================
616 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
617 UFO_ENSURE_NATIVE_ADDR(addr
);
618 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
619 return ufoImage
[addr
];
623 //==========================================================================
627 // 32 for native address
629 //==========================================================================
630 UFO_FORCE_INLINE
uint32_t ufoImgGetCounter (uint32_t addr
) {
631 UFO_ENSURE_NATIVE_ADDR(addr
);
632 return ufoImgGetU32(addr
);
636 //==========================================================================
640 //==========================================================================
641 static FILE *ufoOpenFileOrDir (char **fnameptr
) {
646 if (fnameptr
== NULL
) return NULL
;
649 fprintf(stderr
, "***:fname=<%s>\n", fname
);
652 if (fname
== NULL
|| fname
[0] == 0 || stat(fname
, &st
) != 0) return NULL
;
654 if (S_ISDIR(st
.st_mode
)) {
655 tmp
= calloc(1, strlen(fname
) + 128);
656 ufo_assert(tmp
!= NULL
);
657 sprintf(tmp
, "%s/%s", fname
, "zzmain.f");
658 free(fname
); fname
= tmp
; *fnameptr
= tmp
;
660 fprintf(stderr
, "***: <%s>\n", fname
);
664 return fopen(fname
, "rb");
668 //==========================================================================
672 //==========================================================================
673 static void ufoPushInFile (void) {
674 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
675 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
677 stk
->fname
= ufoInFileName
;
678 stk
->fline
= ufoInFileLine
;
679 stk
->incpath
= ufoLastIncPath
;
680 // save TIB (if it is the default)
681 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
682 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
683 stk
->savedTIBSize
= 0;
684 stk
->savedTIB
= NULL
;
685 if (tib
== 0 && in
< ufoTIBAreaSize
) {
686 while (ufoImgGetU8(tib
+ in
+ stk
->savedTIBSize
) != 0) stk
->savedTIBSize
+= 1;
687 if (stk
->savedTIBSize
!= 0) {
688 stk
->savedTIB
= malloc(stk
->savedTIBSize
);
689 if (stk
->savedTIB
== NULL
) ufoFatal("out of memory for include stack");
690 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
691 stk
->savedTIB
[f
] = ufoImgGetU8(tib
+ in
+ f
);
695 ufoFileStackPos
+= 1;
697 ufoInFileName
= NULL
;
699 ufoLastIncPath
= NULL
;
703 //==========================================================================
707 //==========================================================================
708 static void ufoPopInFile (void) {
709 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
710 if (ufoInFileName
) free(ufoInFileName
);
711 if (ufoInFile
) fclose(ufoInFile
);
712 if (ufoLastIncPath
) free(ufoLastIncPath
);
713 ufoFileStackPos
-= 1;
714 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
716 ufoInFileName
= stk
->fname
;
717 ufoInFileLine
= stk
->fline
;
718 ufoLastIncPath
= stk
->incpath
;
720 // also, restore current line, because some code may need it
721 if (stk
->savedTIBSize
>= ufoTIBAreaSize
) ufoFatal("restored TIB too big");
722 if (stk
->savedTIBSize
>= sizeof(ufoCurrFileLine
)) {
723 ufoFatal("post-include restored source line is too long");
725 ufoImgPutU32(ufoAddrTIB
, 0);
726 ufoImgPutU32(ufoAddrIN
, 0);
727 if (stk
->savedTIBSize
!= 0) {
728 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
729 ufoImgPutU8(f
, stk
->savedTIB
[f
]);
730 ufoCurrFileLine
[f
] = (char)(stk
->savedTIB
[f
]&0xff);
734 ufoImgPutU8(stk
->savedTIBSize
, 0);
735 ufoCurrFileLine
[stk
->savedTIBSize
] = 0;
736 #ifdef UFO_DEBUG_INLCUDE
737 fprintf(stderr
, "INC-POP: <%s>\n", ufoCurrFileLine
);
742 //==========================================================================
746 //==========================================================================
747 void ufoDeinit (void) {
751 if (ufoInFileName
) free(ufoInFileName
);
752 if (ufoLastIncPath
) free(ufoLastIncPath
);
753 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
;
756 while (ufoForthDict
!= NULL
) {
757 UForthWord
*fw
= ufoForthDict
;
758 if (fw
->buckets
!= NULL
) free(fw
->buckets
);
759 ufoForthDict
= fw
->prevAll
;
775 ufoSP
= 0; ufoRP
= 0; ufoRPTop
= 0;
776 ufoLP
= 0; ufoLBP
= 0;
777 ufoMode
= UFO_MODE_NATIVE
;
778 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
787 ufoAddrTIB
= 0; ufoAddrIN
= 0;
789 ufoLastDefinedNativeWord
= NULL
;
791 ufoLastEmitWasCR
= 1;
796 ufoClearCondDefines();
804 // ////////////////////////////////////////////////////////////////////////// //
807 UFO_FORCE_INLINE
uint32_t ufoGetTIB (void) {
808 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrTIB
);
809 return ufoImage
[ufoAddrTIB
];
812 UFO_FORCE_INLINE
void ufoSetTIB (uint32_t value
) {
813 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrTIB
);
814 ufoImage
[ufoAddrTIB
] = value
;
817 UFO_FORCE_INLINE
uint32_t ufoGetIN (void) {
818 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrIN
);
819 return ufoImage
[ufoAddrIN
];
822 UFO_FORCE_INLINE
void ufoSetIN (uint32_t value
) {
823 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrIN
);
824 ufoImage
[ufoAddrIN
] = value
;
829 // ////////////////////////////////////////////////////////////////////////// //
830 // 1: compiling; 0: interpreting
831 UFO_FORCE_INLINE
int ufoGetState (void) { return (int)ufoImgGetU32(ufoSTATEaddr
); }
832 // 1: compiling; 0: interpreting
833 UFO_FORCE_INLINE
void ufoSetState (int v
) { ufoImgPutU32(ufoSTATEaddr
, (uint32_t)v
); }
835 UFO_FORCE_INLINE
void ufoSetStateCompile (void) { ufoSetState(1); }
836 UFO_FORCE_INLINE
void ufoSetStateInterpret (void) { ufoSetState(0); }
838 UFO_FORCE_INLINE
int ufoIsCompiling () { return (ufoGetState() != 0); }
839 UFO_FORCE_INLINE
int ufoIsInterpreting () { return (ufoGetState() == 0); }
842 #define UFO_GET_CFAPROC(cfa_) ({ \
843 uint32_t xcfa = (cfa_); \
844 ((xcfa & UFO_RS_CFA_BIT) && (xcfa & UFO_RS_CFA_MASK) < ufoCFAsUsed ? \
845 ufoForthCFAs[(xcfa & UFO_RS_CFA_MASK)] : NULL); \
848 #define UFO_VALID_VOC_FW(fw_) ({ \
849 const UForthWord *xvfw = (fw_); \
850 (xvfw != NULL && xvfw->cfa == &ufoDoVoc); \
854 //==========================================================================
858 // will not link hidden words
860 //==========================================================================
861 static void ufoLinkWordToDict (UForthWord
*fw
) {
862 ufo_assert(fw
!= NULL
&& fw
->prevAll
== NULL
&& fw
->hash
== 0 && fw
->hlink
== NULL
);
863 ufo_assert(fw
->name
!= NULL
);
864 if (UFW_IS_HID(fw
)) {
868 // insert into hash bucket
869 fw
->hash
= joaatHashBufCI(fw
->name
, strlen(fw
->name
));
870 const uint32_t bucket
= fw
->hash
%UFO_DICT_HASH_BUCKETS
;
872 uint32_t cur
= ufoImgGetU32(ufoAddrCurrent
);
873 // we may have no vocabulary active
874 UForthWord
*voc
= UFO_GET_CFAPROC(cur
);
875 if (UFO_VALID_VOC_FW(voc
)) {
877 fprintf(stderr
, "REG: <%s> : hash=0%08XH; bucked=%u\n", fw
->name
, fw
->hash
, bucket
);
879 fw
->hlink
= voc
->buckets
[bucket
];
880 voc
->buckets
[bucket
] = fw
;
881 fw
->prevVoc
= voc
->latest
;
887 // append to linear list
888 fw
->prevAll
= ufoForthDict
;
893 //==========================================================================
897 //==========================================================================
898 static void ufoLinkVocab (UForthWord
*fw
, UForthWord
*parent
) {
899 if (UFO_VALID_VOC_FW(fw
)) {
900 ufo_assert(fw
->pfa
!= 0xffffffffU
&& FW_GET_CFAIDX(fw
) < ufoCFAsUsed
);
901 if (parent
!= fw
&& UFO_VALID_VOC_FW(parent
)) {
902 ufoImgPutU32(fw
->pfa
+ UFW_VOCAB_OFS_PARENT
, parent
->cfaidx
);
904 ufoImgPutU32(fw
->pfa
+ UFW_VOCAB_OFS_PARENT
, 0);
910 //==========================================================================
912 // ufoCreateVocabData
914 //==========================================================================
915 static void ufoCreateVocabData (UForthWord
*fw
) {
916 if (fw
!= NULL
&& fw
->cfa
== NULL
) {
917 ufo_assert(fw
->pfa
== 0xffffffffU
&& FW_GET_CFAIDX(fw
) < ufoCFAsUsed
&& fw
->buckets
== NULL
);
919 fw
->buckets
= calloc(1, sizeof(fw
->buckets
[0]) * UFO_DICT_HASH_BUCKETS
);
920 // pfa: cfa, parentvoc, prevvoc
921 fw
->pfa
= ufoImageUsed
;
922 fw
->pfastart
= ufoImageUsed
;
923 ufoImgEmitU32(fw
->cfaidx
); // our cfa
924 ufoImgEmitU32(0); // parent voc cfa
925 ufoImgEmitU32(ufoLastVoc
); // voc link
926 ufoLastVoc
= fw
->pfa
;
927 fw
->pfaend
= ufoImageUsed
;
928 ufoLastVoc
= fw
->cfaidx
;
933 //==========================================================================
937 //==========================================================================
938 static UForthWord
*ufoFindWordInVoc (const char *wname
, uint32_t hash
, UForthWord
*voc
,
941 UForthWord
*fw
= NULL
;
942 if (wname
&& wname
[0] != 0 && UFO_VALID_VOC_FW(voc
)) {
943 fw
= voc
->buckets
[hash
%UFO_DICT_HASH_BUCKETS
];
945 uint32_t nlen
= (uint32_t)strlen(wname
);
947 if (fw
->cfa
!= NULL
&& fw
->hash
== hash
&& fw
->namelen
== nlen
&&
948 !UFW_IS_HID(fw
) && (allowvochid
|| !UFW_IS_VOC_HID(fw
)) &&
949 strEquCI(fw
->name
, wname
))
961 //==========================================================================
963 // ufoFindWordNameRes
965 //==========================================================================
966 static UForthWord
*ufoFindWordNameRes (const char *wname
) {
969 //FIXME: make this faster!
971 uint32_t lvcfa
= ufoLastVoc
;
972 UForthWord
*voc
= UFO_GET_CFAPROC(lvcfa
);
973 if (!UFO_VALID_VOC_FW(voc
) || wname
[0] == ':') return NULL
;
975 const char *colon
= strchr(wname
+ 1, ':');
976 if (colon
== NULL
|| colon
[1] == 0 || colon
[1] == ':') return NULL
;
977 size_t vnlen
= (size_t)(colon
- wname
);
978 if (vnlen
> 255) return NULL
;
980 // get initial vocabulary name
981 memcpy(tempwbuf
, wname
, vnlen
);
983 wname
= colon
+ 1; // skip colon
986 fprintf(stderr
, "NRES: INIT-VOC=<%s>; REST=<%s>\n", tempwbuf
, wname
);
989 uint32_t vhash
= joaatHashBufCI(tempwbuf
, vnlen
);
990 while (UFO_VALID_VOC_FW(voc
)) {
991 if (voc
->hash
== vhash
&& voc
->namelen
== vnlen
&& strEquCI(voc
->name
, tempwbuf
)) {
994 lvcfa
= ufoImgGetU32(voc
->pfa
+ 2);
995 voc
= UFO_GET_CFAPROC(lvcfa
);
999 fprintf(stderr
, " IVC: %p %d\n", voc
, UFO_VALID_VOC_FW(voc
));
1002 while (wname
!= NULL
&& UFO_VALID_VOC_FW(voc
)) {
1003 vhash
= joaatHashBufCI(wname
, strlen(wname
));
1004 fw
= ufoFindWordInVoc(wname
, vhash
, voc
, 1);
1005 if (fw
!= NULL
) return fw
;
1006 colon
= strchr(wname
, ':');
1007 if (colon
== NULL
) return NULL
;
1009 size_t vnlen
= (size_t)(colon
- wname
);
1010 if (vnlen
> 255) return NULL
;
1011 memcpy(tempwbuf
, wname
, vnlen
);
1012 tempwbuf
[vnlen
] = 0;
1013 wname
= colon
+ 1; // skip colon
1015 fprintf(stderr
, " XVOC=<%s>; XREST=<%s>\n", tempwbuf
, wname
);
1017 vhash
= joaatHashBufCI(tempwbuf
, vnlen
);
1018 voc
= ufoFindWordInVoc(tempwbuf
, vhash
, voc
, 1);
1025 //==========================================================================
1029 // ignore words with no CFA: those are not finished yet
1031 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
1033 //==========================================================================
1034 static UForthWord
*ufoFindWord (const char *wname
) {
1035 if (!wname
|| wname
[0] == 0) return NULL
;
1036 uint32_t cur
= ufoImgGetU32(ufoAddrContext
);
1037 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1041 // first search in current
1042 voc
= UFO_GET_CFAPROC(cur
);
1043 fw
= ufoFindWordInVoc(wname
, hash
, voc
, (cur
== ufoImgGetU32(ufoAddrContext
)));
1046 if (fw
== NULL
&& UFO_VALID_VOC_FW(voc
)) {
1047 uint32_t vocPPrev
= cur
;
1049 while (fw
== NULL
&& UFO_VALID_VOC_FW(voc
)) {
1050 uint32_t vocParent
= ufoImgGetU32(voc
->pfa
+ UFW_VOCAB_OFS_PARENT
);
1051 if (vocParent
== vocPPrev
) break;
1052 // move prev pointer
1054 voc
= UFO_GET_CFAPROC(vocPPrev
);
1055 ufo_assert(UFO_VALID_VOC_FW(voc
));
1056 vocPPrev
= ufoImgGetU32(voc
->pfa
+ UFW_VOCAB_OFS_PARENT
);
1060 voc
= UFO_GET_CFAPROC(vocParent
);
1061 fw
= ufoFindWordInVoc(wname
, hash
, voc
, (cur
== ufoImgGetU32(ufoAddrContext
)));
1065 // if not found, try name resolution
1066 if (fw
== NULL
) fw
= ufoFindWordNameRes(wname
);
1068 // now try vocabulary stack
1069 uint32_t vstp
= ufoVSP
;
1070 while (fw
== NULL
&& vstp
!= 0) {
1072 voc
= UFO_GET_CFAPROC(ufoVocStack
[vstp
]);
1073 fw
= ufoFindWordInVoc(wname
, hash
, voc
,
1074 (ufoVocStack
[vstp
] == ufoImgGetU32(ufoAddrContext
)));
1081 //==========================================================================
1085 //==========================================================================
1086 static UForthWord
*ufoFindWordMacro (const char *wname
) {
1087 if (!wname
|| wname
[0] == 0) return NULL
;
1088 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1089 return ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoMacroVocCFA
), 0);
1093 //==========================================================================
1097 // only in FORTH dictionary, including hidden words
1099 //==========================================================================
1100 static UForthWord
*ufoFindWordForth (const char *wname
) {
1101 if (!wname
|| wname
[0] == 0) return NULL
;
1102 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1103 UForthWord
*fw
= ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoForthVocCFA
), 1);
1104 if (fw
== NULL
) fw
= ufoFindWord(wname
);
1109 //==========================================================================
1111 // ufoFindWordCompiler
1113 //==========================================================================
1114 static UForthWord
*ufoFindWordCompiler (const char *wname
) {
1115 if (!wname
|| wname
[0] == 0) return NULL
;
1116 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1117 UForthWord
*fw
= ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoCompSuppVocCFA
), 1);
1118 if (fw
== NULL
) fw
= ufoFindWord(wname
);
1123 //==========================================================================
1125 // ufoAlwaysWordForth
1127 //==========================================================================
1128 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWordForth (const char *wname
) {
1129 UForthWord
*fw
= ufoFindWordForth(wname
);
1130 if (!fw
) ufoFatal("FORTH word `%s` not found", (wname
[0] ? wname
: "~"));
1135 //==========================================================================
1137 // ufoAlwaysWordCompiler
1139 //==========================================================================
1140 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWordCompiler (const char *wname
) {
1141 UForthWord
*fw
= ufoFindWordCompiler(wname
);
1142 if (!fw
) ufoFatal("COMPILER word `%s` not found", (wname
[0] ? wname
: "~"));
1147 //==========================================================================
1151 //==========================================================================
1152 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWord (const char *wname
) {
1153 UForthWord
*fw
= ufoFindWord(wname
);
1154 if (!fw
) ufoFatal("word `%s` not found", (wname
[0] ? wname
: "~"));
1159 //==========================================================================
1163 //==========================================================================
1164 static UForthWord
*ufoNFind (uint32_t addr
, uint32_t count
) {
1167 if (count
> 127) return NULL
; // too long
1169 for (uint32_t n
= 0; n
< count
; ++n
) {
1170 const uint8_t ch
= ufoImgGetU8(addr
+n
)&0xffU
;
1171 if (!ch
) return NULL
; // word name cannot contain 0 byte
1172 wbuf
[n
] = (char)ch
; //toUpper((char)(ch));
1176 return ufoFindWord(wbuf
);
1180 //==========================================================================
1182 // ufoLoadNextLine_NativeMode
1184 // load next file line into TIB
1185 // always adds final '\n'
1187 //==========================================================================
1188 static void ufoLoadNextLine_NativeMode (int crossInclude
) {
1189 const uint8_t *text
= NULL
;
1191 ufoSetTIB(0); ufoSetIN(0);
1194 while (ufoInFile
&& done
== 0) {
1195 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
1196 // check for a newline
1197 // if there is no newline char at the end, the string was truncated
1198 ufoCurrFileLine
[510] = 0;
1199 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
1200 if (slen
== 0 || (ufoCurrFileLine
[slen
- 1u] != 13 && ufoCurrFileLine
[slen
- 1u] != 10)) {
1201 ufoFatal("input line too long");
1204 text
= (const uint8_t *)ufoCurrFileLine
;
1207 if (!crossInclude
) {
1208 if (ufoCondStLine
>= 0) {
1209 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1211 ufoFatal("unexpected end of text");
1220 text
= (const uint8_t *)ufoGetSrcLine(&fname
, &lnum
);
1222 if (ufoCondStLine
>= 0) {
1223 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1225 ufoFatal("unexpected end of text");
1227 ufoInFileLine
= lnum
;
1228 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1229 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1230 ufoInFileName
= strdup(fname
);
1231 setLastIncPath(ufoInFileName
);
1235 size_t sslen
= strlen((const char *)text
);
1236 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1237 if (sslen
> 510) ufoFatal("input line too long");
1238 if (text
!= (const void *)ufoCurrFileLine
) {
1239 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1241 ufoCurrFileLine
[sslen
+ 0] = 10;
1242 ufoCurrFileLine
[sslen
+ 1] = 0;
1244 #ifdef UFO_DEBUG_INLCUDE
1245 fprintf(stderr
, "NEXT-LINE: <%s>\n", ufoCurrFileLine
);
1248 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1249 uint8_t ch
= text
[dpos
];
1250 // replace bad chars, because why not
1251 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1252 ufoImgPutU32(dpos
, ch
);
1254 ufoImgPutU32((uint32_t)sslen
, 10);
1255 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1259 //==========================================================================
1263 //==========================================================================
1264 static void ufoLoadMacroLine (const char *line
, const char *fname
, int lnum
) {
1265 const uint8_t *text
= (const uint8_t *)line
;
1266 if (text
== NULL
) text
= (const uint8_t *)"";
1267 if (fname
== NULL
) fname
= "";
1269 ufoSetTIB(0); ufoSetIN(0);
1271 ufoInFileLine
= lnum
;
1272 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1273 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1274 ufoInFileName
= strdup(fname
);
1275 setLastIncPath(ufoInFileName
);
1278 size_t sslen
= strlen((const char *)text
);
1279 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1280 if (sslen
> 510) ufoFatal("input line too long");
1281 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1282 ufoCurrFileLine
[sslen
+ 0] = 10;
1283 ufoCurrFileLine
[sslen
+ 1] = 0;
1285 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1286 uint8_t ch
= text
[dpos
];
1287 // replace bad chars, because why not
1288 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1289 ufoImgPutU32(dpos
, ch
);
1291 ufoImgPutU32((uint32_t)sslen
, 10);
1292 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1296 //==========================================================================
1300 // load next file line into TIB
1301 // return zero on success, -1 on EOF, -2 on error
1303 //==========================================================================
1304 static void ufoLoadNextLine (int crossInclude
) {
1306 case UFO_MODE_NATIVE
:
1307 ufoLoadNextLine_NativeMode(crossInclude
);
1309 case UFO_MODE_MACRO
:
1310 if (ufoCondStLine
>= 0) {
1311 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1313 ufoFatal("unexpected end of input for FORTH asm macro");
1315 default: ufoFatal("wtf?! not properly inited!");
1320 // ////////////////////////////////////////////////////////////////////////// //
1321 // working with the stacks
1322 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("UFO data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
1323 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); --ufoSP
; }
1324 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("UFO data stack underflow"); } return ufoDStack
[--ufoSP
]; }
1325 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
1326 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
1327 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
1328 UFO_FORCE_INLINE
void ufoSwap (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = t
; }
1329 UFO_FORCE_INLINE
void ufoRot (void) { if (ufoSP
< 3u) ufoFatal("UFO 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
; }
1330 UFO_FORCE_INLINE
void ufoNRot (void) { if (ufoSP
< 3u) ufoFatal("UFO 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
; }
1332 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
1333 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
1334 UFO_FORCE_INLINE
void ufo2Over (void) { if (ufoSP
< 4u) ufoFatal("UFO data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoPush(n0
); ufoPush(n1
); }
1335 UFO_FORCE_INLINE
void ufo2Swap (void) { if (ufoSP
< 4u) ufoFatal("UFO 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
; }
1337 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("UFO return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
1338 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); --ufoRP
; }
1339 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[--ufoRP
]; }
1340 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
1341 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
1342 UFO_FORCE_INLINE
void ufoROver (void) { if (ufoRP
< 2u) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-2u]); }
1343 UFO_FORCE_INLINE
void ufoRSwap (void) { if (ufoRP
< 2u) ufoFatal("UFO return stack underflow"); const uint32_t t
= ufoRStack
[ufoRP
-1u]; ufoRStack
[ufoRP
-1u] = ufoRStack
[ufoRP
-2u]; ufoRStack
[ufoRP
-2u] = t
; }
1344 UFO_FORCE_INLINE
void ufoRRot (void) { if (ufoRP
< 3u) ufoFatal("UFO return stack underflow"); const uint32_t t
= ufoRStack
[ufoRP
-3u]; ufoRStack
[ufoRP
-3u] = ufoRStack
[ufoRP
-2u]; ufoRStack
[ufoRP
-2u] = ufoRStack
[ufoRP
-1u]; ufoRStack
[ufoRP
-1u] = t
; }
1345 UFO_FORCE_INLINE
void ufoRNRot (void) { if (ufoRP
< 3u) ufoFatal("UFO return stack underflow"); const uint32_t t
= ufoRStack
[ufoRP
-1u]; ufoRStack
[ufoRP
-1u] = ufoRStack
[ufoRP
-2u]; ufoRStack
[ufoRP
-2u] = ufoRStack
[ufoRP
-3u]; ufoRStack
[ufoRP
-3u] = t
; }
1347 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
1350 // ////////////////////////////////////////////////////////////////////////// //
1351 #define UFWORD(name_) \
1352 static void ufoWord_##name_ (UForthWord *self)
1354 #define UFCALL(name_) ufoWord_##name_(NULL)
1355 #define UFCFA(name_) (&ufoWord_##name_)
1359 // ////////////////////////////////////////////////////////////////////////// //
1360 static void ufoDoForth (UForthWord
*self
) {
1362 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1363 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1366 if (self
->pfastart
!= self
->pfa
) {
1368 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1369 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1371 ufoPush(self
->pfastart
);
1377 //==========================================================================
1381 //==========================================================================
1382 static void ufoDoVoc (UForthWord
*self
) {
1383 ufoImgPutU32(ufoAddrContext
, self
->cfaidx
);
1387 //==========================================================================
1389 // ufoCompileWordCFA
1391 //==========================================================================
1392 UFO_FORCE_INLINE
void ufoCompileWordCFA (UForthWord
*fw
) {
1393 if (fw
== NULL
) ufoFatal("internal error in `ufoCompileWordCFA`");
1394 if (fw
->cfa
== NULL
|| FW_GET_CFAIDX(fw
) >= ufoCFAsUsed
) {
1395 ufoFatal("internal error in `ufoCompileWordCFA` (word: '%s')", fw
->name
);
1397 ufoImgEmitU32(fw
->cfaidx
);
1401 //==========================================================================
1403 // ufoCompileForthWord
1405 //==========================================================================
1406 UFO_FORCE_INLINE
void ufoCompileForthWord (const char *wname
) {
1407 ufoCompileWordCFA(ufoAlwaysWordForth(wname
));
1411 //==========================================================================
1413 // ufoCompileCompilerWord
1415 //==========================================================================
1416 UFO_FORCE_INLINE
void ufoCompileCompilerWord (const char *wname
) {
1417 ufoCompileWordCFA(ufoAlwaysWordCompiler(wname
));
1421 //==========================================================================
1423 // ufoCompileLiteral
1425 //==========================================================================
1426 static void ufoCompileLiteral (uint32_t value
) {
1427 ufoCompileCompilerWord("LIT");
1428 ufoImgEmitU32(value
);
1432 // ////////////////////////////////////////////////////////////////////////// //
1435 UFWORD(SP0_PUT
) { ufoSP
= 0; }
1439 UFWORD(RP0_PUT
) { ufoRP
= ufoRPTop
; }
1443 UFWORD(BASE
) { ufoPush(ufoBASEaddr
); }
1447 UFWORD(STATE
) { ufoPush(ufoSTATEaddr
); }
1450 // ( addr -- value32 )
1451 UFWORD(PEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)); }
1454 // ( addr -- value8 )
1455 UFWORD(CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU8(addr
)&0xffU
); }
1458 // ( addr -- value32 )
1459 UFWORD(WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)&0xffffU
); }
1462 // ( val32 addr -- )
1463 UFWORD(POKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU32(addr
, val
); }
1467 UFWORD(CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU8(addr
, val
&0xffU
); }
1470 // ( val32 addr -- )
1472 const uint32_t addr
= ufoPop();
1473 const uint32_t val
= ufoPop();
1474 ufoImgPutU32(addr
, val
&0xffffU
);
1479 // puts byte to native/zx dictionary, according to the current mode
1481 const uint32_t val
= ufoPop()&0xffU
;
1487 // puts byte to zx dictionary
1489 const uint32_t val
= ufoPop()&0xffU
;
1495 // puts uint/word to native/zx dictionary, according to the current mode
1497 const uint32_t val
= ufoPop();
1503 // puts word to zx dictionary
1505 const uint32_t val
= ufoPop();
1506 ufoZXEmitU16(val
&0xffffU
);
1510 // ( addr -- value8 )
1511 UFWORD(ZX_CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU8(addr
)); }
1515 UFWORD(ZX_CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU8(addr
, val
); }
1518 // ( addr -- value16 )
1519 UFWORD(ZX_WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU16(addr
)); }
1522 // ( val16 addr -- )
1523 UFWORD(ZX_WPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU16(addr
, val
); }
1527 UFWORD(ZX_RESERVEDQ
) {
1528 const uint32_t addr
= ufoPop();
1529 ufoPushBool(ufoZXGetReserved(addr
));
1534 UFWORD(ZX_RESERVEDS
) {
1535 const uint32_t addr
= ufoPop();
1536 const uint32_t flag
= ufoPop();
1537 ufoZXSetReserved(addr
, (flag
? 1 : 0));
1543 // is address a ZX Spectrum mmaped address?
1545 const uint32_t addr
= ufoPop();
1546 ufoPushBool(addr
&UFO_ZX_ADDR_BIT
);
1551 // convert address to ZX Spectrum mmaped address
1553 const uint32_t addr
= ufoPop();
1554 ufoPush((addr
&UFO_ZX_ADDR_MASK
)|UFO_ZX_ADDR_BIT
);
1559 // convert address to ZX Spectrum mmaped address
1561 if (ufoMode
== UFO_MODE_NATIVE
) {
1562 if (ufoIsCompiling()) {
1563 ufoCompileForthWord("(TOZX)");
1572 // convert address from ZX Spectrum mmaped address
1574 const uint32_t addr
= ufoPop();
1575 ufoPush(addr
&UFO_ZX_ADDR_MASK
);
1580 // convert address from ZX Spectrum mmaped address
1581 UFWORD(FROMZX_IMM
) {
1582 if (ufoMode
== UFO_MODE_NATIVE
) {
1583 if (ufoIsCompiling()) {
1584 ufoCompileForthWord("(FROMZX)");
1593 const uint32_t v
= ufoImgGetU32(ufoIP
++);
1599 ufoIP
= ufoImgGetU32(ufoIP
);
1602 // (TBRANCH) ( flag )
1605 ufoIP
= ufoImgGetU32(ufoIP
);
1611 // (0BRANCH) ( flag )
1614 ufoIP
= ufoImgGetU32(ufoIP
);
1621 // ( limit start -- | limit counter )
1622 // loops from start to limit-1
1629 // ( -- | limit counter )
1630 static void ufoPLoopCommon (int32_t add
) {
1631 const int32_t n
= (int32_t)ufoRPop();
1632 const int32_t lim
= (int32_t)ufoRPeek();
1633 const int32_t newn
= n
+add
;
1634 // this is how dsForth does it
1635 if ((newn
< 0 ? lim
-newn
: newn
-lim
) < 0) {
1637 ufoIP
= ufoImgGetU32(ufoIP
);
1645 // ( -- | limit counter )
1646 // loops from start to limit-1
1647 UFWORD(LOOP_PAREN
) {
1652 // ( n -- | limit counter )
1653 // loops from start to limit-1
1654 UFWORD(PLOOP_PAREN
) {
1655 const int32_t add
= (int32_t)ufoPop();
1656 ufoPLoopCommon(add
);
1663 const int32_t add = (int32_t)ufoPop();
1664 int32_t n = (int32_t)ufoRPop();
1665 const int32_t lim = (int32_t)ufoRPeek();
1666 if ((n < lim && n+add >= lim) || (n > lim && n+add <= lim)) {
1671 ufoIP = ufoImgGetU32(ufoIP);
1677 // ( counter -- | limit counter )
1679 ufoPush(ufoRPeek());
1683 // ( limit -- | limit counter )
1685 const uint32_t c
= ufoRPop();
1686 ufoPush(ufoRPeek());
1692 const uint32_t c0
= ufoRPop();
1693 const uint32_t c1
= ufoRPop();
1694 ufoPush(ufoRPeek());
1701 const uint32_t c0
= ufoRPop();
1702 const uint32_t c1
= ufoRPop();
1703 const uint32_t c2
= ufoRPop();
1704 ufoPush(ufoRPeek());
1711 //==========================================================================
1713 // ufoExecuteNativeWordInVM
1715 //==========================================================================
1716 UFO_FORCE_INLINE
void ufoExecuteNativeWordInVM (UForthWord
*fw
) {
1717 ufo_assert(fw
!= NULL
);
1718 if (fw
->cfa
== &ufoDoForth
) {
1719 const uint32_t oldRPTop
= ufoRPTop
;
1721 fw
->cfa(fw
); // this pushes IP, and may do other work
1723 ufoRPTop
= oldRPTop
;
1730 //==========================================================================
1734 //==========================================================================
1735 UFO_FORCE_INLINE
void ufoExecCFAIdxInVM (uint32_t cfa
) {
1736 if (cfa
& UFO_RS_CFA_BIT
) {
1737 cfa
&= UFO_RS_CFA_MASK
;
1738 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1739 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1740 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1741 ufoExecuteNativeWordInVM(fw
);
1743 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1748 //==========================================================================
1752 //==========================================================================
1753 UFO_FORCE_INLINE
void ufoExecCFAIdx (uint32_t cfa
) {
1754 if (cfa
& UFO_RS_CFA_BIT
) {
1755 cfa
&= UFO_RS_CFA_MASK
;
1756 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1757 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1758 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1761 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1767 UFWORD(EXECUTE
) { ufoExecCFAIdx(ufoPop()); }
1770 UFWORD(DUP
) { ufoDup(); }
1771 // ?DUP ( n -- n n ) | ( 0 -- 0 )
1772 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
1773 // 2DUP ( n0 n1 -- n0 n1 n0 n1 ) | ( 0 -- 0 )
1774 UFWORD(DDUP
) { ufo2Dup(); }
1776 UFWORD(DROP
) { ufoDrop(); }
1778 UFWORD(DDROP
) { ufo2Drop(); }
1779 // SWAP ( n0 n1 -- n1 n0 )
1780 UFWORD(SWAP
) { ufoSwap(); }
1781 // 2SWAP ( n0 n1 -- n1 n0 )
1782 UFWORD(DSWAP
) { ufo2Swap(); }
1783 // OVER ( n0 n1 -- n0 n1 n0 )
1784 UFWORD(OVER
) { ufoOver(); }
1785 // 2OVER ( n0 n1 -- n0 n1 n0 )
1786 UFWORD(DOVER
) { ufo2Over(); }
1787 // ROT ( n0 n1 n2 -- n1 n2 n0 )
1788 UFWORD(ROT
) { ufoRot(); }
1789 // NROT ( n0 n1 n2 -- n2 n0 n1 )
1790 UFWORD(NROT
) { ufoNRot(); }
1792 // RDUP ( n -- n n )
1793 UFWORD(RDUP
) { ufoRDup(); }
1795 UFWORD(RDROP
) { ufoRDrop(); }
1796 // RSWAP ( n0 n1 -- n1 n0 )
1797 UFWORD(RSWAP
) { ufoRSwap(); }
1798 // ROVER ( n0 n1 -- n0 n1 n0 )
1799 UFWORD(ROVER
) { ufoROver(); }
1800 // RROT ( n0 n1 n2 -- n1 n2 n0 )
1801 UFWORD(RROT
) { ufoRRot(); }
1802 // RNROT ( n0 n1 n2 -- n2 n0 n1 )
1803 UFWORD(RNROT
) { ufoRNRot(); }
1806 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
1807 // R> ( -- n | n-removed )
1808 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
1809 // R@ ( -- n | n-removed )
1810 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
1814 // ( src dest count -- )
1816 uint32_t count
= ufoPop();
1817 uint32_t dest
= ufoPop();
1818 uint32_t src
= ufoPop();
1819 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1825 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? ufoZXGetU8(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1826 if (dest
&UFO_ZX_ADDR_BIT
) ufoZXPutU8(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1831 // ( src dest count -- )
1832 UFWORD(CMOVE_BACK
) {
1833 uint32_t count
= ufoPop();
1834 uint32_t dest
= ufoPop();
1835 uint32_t src
= ufoPop();
1836 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1838 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? ufoZXGetU8(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1839 if (dest
&UFO_ZX_ADDR_BIT
) ufoZXPutU8(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1846 // ( src dest count -- )
1848 uint32_t count
= ufoPop();
1849 uint32_t dest
= ufoPop();
1850 uint32_t src
= ufoPop();
1854 if (dest
< src
) UFCALL(CMOVE_BACK
); else UFCALL(CMOVE_FWD
);
1859 // ( addr count val -- )
1861 uint32_t val
= ufoPop();
1862 int32_t count
= (int32_t)ufoPop();
1863 uint32_t dest
= ufoPop();
1865 ufoImgPutU32(dest
, val
);
1866 dest
+= 1; count
-= 1;
1872 // ( addr1 count1 addr2 count2 -- flag )
1874 uint32_t count2
= ufoPop();
1875 uint32_t addr2
= ufoPop();
1876 uint32_t count1
= ufoPop();
1877 uint32_t addr1
= ufoPop();
1878 if (count2
!= count1
) { ufoPushBool(0); return; }
1880 uint8_t c0
= ufoImgGetU8(addr1
++);
1881 uint8_t c1
= ufoImgGetU8(addr2
++);
1882 if (c0
!= c1
) { ufoPushBool(0); return; }
1888 // ( addr1 count1 addr2 count2 -- flag )
1890 uint32_t count2
= ufoPop();
1891 uint32_t addr2
= ufoPop();
1892 uint32_t count1
= ufoPop();
1893 uint32_t addr1
= ufoPop();
1894 if (count2
!= count1
) { ufoPushBool(0); return; }
1896 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1897 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1898 if (c0
!= c1
) { ufoPushBool(0); return; }
1904 // ( addr1 count1 addr2 count2 -- signed-flag )
1906 uint32_t count2
= ufoPop();
1907 uint32_t addr2
= ufoPop();
1908 uint32_t count1
= ufoPop();
1909 uint32_t addr1
= ufoPop();
1910 while (count1
!= 0 && count2
!= 0) {
1911 uint8_t c0
= ufoImgGetU8(addr1
++);
1912 uint8_t c1
= ufoImgGetU8(addr2
++);
1914 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1918 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1919 else if (count2
== 0) ufoPush(1u);
1920 else __builtin_trap();
1924 // ( addr1 count1 addr2 count2 -- flag )
1926 uint32_t count2
= ufoPop();
1927 uint32_t addr2
= ufoPop();
1928 uint32_t count1
= ufoPop();
1929 uint32_t addr1
= ufoPop();
1930 while (count1
!= 0 && count2
!= 0) {
1931 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1932 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1934 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1938 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1939 else if (count2
== 0) ufoPush(1u);
1940 else __builtin_trap();
1944 // ////////////////////////////////////////////////////////////////////////// //
1945 // text input buffer parsing
1947 //==========================================================================
1951 //==========================================================================
1952 UFO_FORCE_INLINE
uint32_t ufoTibCharAddr (void) {
1953 return ufoGetTIB() + ufoGetIN();
1957 //==========================================================================
1961 //==========================================================================
1962 UFO_FORCE_INLINE
uint8_t ufoPeekInChar (void) {
1963 return ufoImgGetU8(ufoTibCharAddr());
1967 //==========================================================================
1971 //==========================================================================
1972 UFO_FORCE_INLINE
uint8_t ufoGetInChar (void) {
1973 const uint32_t tib
= ufoGetTIB();
1974 const uint32_t in
= ufoGetIN();
1975 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1976 if (ch
!= 0) ufoSetIN(in
+ 1);
1981 //==========================================================================
1983 // ufoGetInCharAndAddr
1985 //==========================================================================
1986 UFO_FORCE_INLINE
uint8_t ufoGetInCharAndAddr (uint32_t *addr
) {
1987 const uint32_t tib
= ufoGetTIB();
1988 const uint32_t in
= ufoGetIN();
1990 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1991 if (ch
!= 0) ufoSetIN(in
+ 1);
1998 UFWORD(TIB_ADVANCE_LINE
) {
2004 UFWORD(TIB_PEEKCH
) {
2005 ufoPush(ufoPeekInChar());
2010 UFWORD(TIB_SKIPCH
) {
2011 (void)ufoGetInChar();
2017 ufoPush(ufoGetInChar());
2022 UFWORD(GET_IN_ADDR
) { ufoPush(ufoAddrIN
); }
2026 UFWORD(GET_TIB_ADDR
) { ufoPush(ufoAddrTIB
); }
2029 // ( -- size-in-cells )
2030 UFWORD(GET_TIB_SIZE
) { ufoPush(ufoTIBAreaSize
); }
2036 ufoPush(ufoImageUsed
);
2040 // ( -- n+UFO_PAD_OFFSET,aligned to 1kb )
2042 ufoPush(ufoPadAddr());
2048 uint32_t addr
= ufoPop();
2049 uint32_t len
= ufoImgGetCounter(addr
);
2055 //==========================================================================
2057 // ufoWordIsGoodDelim
2059 //==========================================================================
2060 UFO_FORCE_INLINE
int ufoWordIsGoodDelim (uint32_t ch
, uint32_t delim
) {
2061 return (ch
== delim
|| (delim
== 32 && ch
<= 32));
2066 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
2067 // does base TIB parsing; never copies anything.
2068 // as our reader is line-based, returns FALSE on EOL.
2069 // EOL is detected after skipping leading delimiters.
2070 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2071 // trailing delimiter is always skipped.
2073 const uint32_t skipLeading
= ufoPop();
2074 uint32_t delim
= ufoPop();
2075 uint32_t addr
= 0, count
;
2078 if (delim
> 255) ufoFatal("invalid delimiter char");
2081 #ifdef UFO_DEBUG_PARSE
2082 fprintf(stderr
, "*** (PARSE): delim=%u(%c); skip=%u\n", delim
, (char)delim
, skipLeading
);
2084 ch
= ufoGetInCharAndAddr(&addr
);
2085 #ifdef UFO_DEBUG_PARSE
2086 fprintf(stderr
, " FCH: %u(%c)\n", ch
, (ch
> 32 && ch
< 127 ? (char)ch
: '?'));
2088 // skip leading delimiters
2089 while (ch
!= 0 && skipLeading
&& ufoWordIsGoodDelim(ch
, delim
)) ch
= ufoGetInCharAndAddr(&addr
);
2092 #ifdef UFO_DEBUG_PARSE
2093 fprintf(stderr
, " COLLECT: %u\n", ch
);
2096 while (ch
!= 0 && !ufoWordIsGoodDelim(ch
, delim
)) { count
+= 1; ch
= ufoGetInChar(); }
2097 #ifdef UFO_DEBUG_PARSE
2098 fprintf(stderr
, " COLLECTED: ch=%u; count=%u; addr=%u\n", ch
, count
, addr
);
2104 #ifdef UFO_DEBUG_PARSE
2105 fprintf(stderr
, " EOL!\n");
2110 // skip the whole line
2111 while (ufoGetInChar() != 0) {}
2117 // ( delim skip-leading-delim? -- here TRUE / FALSE )
2118 // parse word, copy it to HERE as counted string.
2119 // adds trailing zero after the string, but doesn't include it in count.
2120 // doesn't advance line.
2121 UFWORD(PAR_WORD_OR_PARSE
) {
2124 uint32_t count
= ufoPop();
2125 uint32_t src
= ufoPop();
2127 uint32_t dest
= ufoPop();
2128 ufoImgPutU32(dest
, count
);
2129 for (uint32_t f
= 0; f
< count
; f
+= 1) {
2130 ufoImgPutU8(dest
+ f
+ 1, ufoImgGetU8(src
+ f
));
2132 ufoImgPutU32(dest
+ count
+ 1, 0); // put trailing zero, just in case
2141 // ( delim -- here )
2142 // parse word, copy it to HERE as counted string.
2143 // adds trailing zero after the string, but doesn't include it in count.
2144 // doesn't advance line.
2145 // return empty string on EOL.
2148 UFCALL(PAR_WORD_OR_PARSE
);
2151 uint32_t dest
= ufoPop();
2152 ufoImgPutU32(dest
, 0); // counter
2153 ufoImgPutU32(dest
+ 1, 0); // trailing zero
2159 // ( delim -- addr count TRUE / FALSE )
2160 // parse word w/o skipping delimiters, copy it to HERE as counted string.
2161 // adds trailing zero after the string, but doesn't include it in count.
2162 // doesn't advance line.
2163 UFWORD(PARSE_TO_HERE
) {
2165 UFCALL(PAR_WORD_OR_PARSE
);
2175 // ( -- addr count )
2176 // parse with skipping leading blanks. doesn't copy anything.
2177 // return empty string on EOL.
2178 UFWORD(PARSE_NAME
) {
2179 ufoPush(32); ufoPushBool(1);
2182 ufoPush(ufoTibCharAddr());
2188 // ( delim -- addr count TRUE / FALSE )
2189 // parse without skipping delimiters; never copies anything.
2190 // as our reader is line-based, returns FALSE on EOL.
2191 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2192 // trailing delimiter is always skipped.
2199 //==========================================================================
2201 // ufoPopStrLitToTempBuf
2203 //==========================================================================
2204 static void ufoPopStrLitToTempBuf (void) {
2205 uint32_t count
= ufoPop();
2206 uint32_t addr
= ufoPop();
2207 if (count
== 0) ufoFatal("unexpected end of line");
2208 ufo_assert(count
< (uint32_t)sizeof(ufoTempCharBuf
));
2210 while (dpos
!= count
) {
2211 ufoTempCharBuf
[dpos
] = ufoImgGetU8(addr
+ dpos
);
2214 ufoTempCharBuf
[dpos
] = 0;
2218 //==========================================================================
2220 // ufoParseNameToTempBuf
2222 // parse forth word name from TIB, put it to `ufoTempCharBuf`.
2223 // on EOL, `ufoTempCharBuf` will be an empty string.
2225 //==========================================================================
2226 static void ufoParseNameToTempBuf (void) {
2228 if (ufoPeek() == 0) ufoFatal("word name expected");
2229 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2230 ufoPopStrLitToTempBuf();
2234 //==========================================================================
2236 // ufoParseNameToTempBufEmptyOk
2238 //==========================================================================
2239 static void ufoParseNameToTempBufEmptyOk (void) {
2241 if (ufoPeek() == 0) {
2242 ufoTempCharBuf
[0] = 0;
2244 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2245 ufoPopStrLitToTempBuf();
2250 //==========================================================================
2252 // ufoPutTempStrLiteral
2254 // puts counted string literal to PAD
2255 // returns VM address of counted string
2257 //==========================================================================
2258 static uint32_t ufoPutTempStrLiteral (const char *s
) {
2260 const size_t slen
= strlen(s
);
2261 if (slen
> 1024*1024) ufoFatal("temp string too long");
2262 uint32_t dest
= ufoPadAddr();
2263 ufoImgPutU32(dest
, (uint32_t)slen
);
2264 for (size_t f
= 0; f
<= slen
; ++f
) {
2265 ufoImgPutU32(dest
+ f
+ 1, (uint8_t)(s
[f
]&0xffU
));
2271 // ////////////////////////////////////////////////////////////////////////// //
2277 uint32_t ch
= ufoPop()&0xffU
;
2278 if (ch
< 32 || ch
== 127) {
2279 if (ch
!= 10 && ch
!= 13 && ch
!= 9) { printf("?"); return; }
2281 ufoLastEmitWasCR
= (ch
== 10);
2282 if (ch
== 10) printf("\n"); else printf("%c", (char)ch
);
2288 uint32_t ch
= ufoPop()&0xffU
;
2289 printf("%c", (ch
< 32 || ch
== 127 ? '?' : (char)ch
));
2290 ufoLastEmitWasCR
= 0;
2297 ufoLastEmitWasCR
= 1;
2304 ufoLastEmitWasCR
= 0;
2310 int32_t n
= (int32_t)ufoPop();
2311 while (n
-- > 0) printf(" ");
2312 ufoLastEmitWasCR
= 0;
2318 if (!ufoLastEmitWasCR
) {
2320 ufoLastEmitWasCR
= 1;
2327 ufoPushBool(ufoLastEmitWasCR
);
2333 ufoLastEmitWasCR
= !!ufoPop();
2337 // ( addr count -- )
2339 int32_t count
= (int32_t)ufoPop();
2340 uint32_t addr
= ufoPop();
2341 while (count
-- > 0) {
2342 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2349 // ( addr count -- )
2351 int32_t count
= (int32_t)ufoPop();
2352 uint32_t addr
= ufoPop();
2353 while (count
-- > 0) {
2354 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2361 UFWORD(STRQ_PAREN
) {
2362 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2364 if (count
> 0x7fffffffU
) ufoPush(0); else ufoPush(count
);
2369 UFWORD(STRDOTQ_PAREN
) {
2370 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2378 //==========================================================================
2380 // ufoNTWordAddrCount
2382 //==========================================================================
2383 static UForthWord
*ufoNTWordAddrCount (void) {
2384 uint32_t count
= ufoPop();
2385 uint32_t addr
= ufoPop();
2386 UForthWord
*fw
= ufoNFind(addr
, count
);
2388 UFCALL(SPACE
); ufoPush(addr
); ufoPush(count
); UFCALL(XTYPE
);
2389 printf(" -- wut?\n"); ufoLastEmitWasCR
= 1;
2390 ufoFatal("unknown UFO word");
2396 // ////////////////////////////////////////////////////////////////////////// //
2399 //==========================================================================
2403 //==========================================================================
2404 static char *ufoPrintNumber (uint32_t v
, int sign
) {
2405 static char buf
[64];
2406 size_t bufpos
= sizeof(buf
);
2408 int64_t n
= (sign
? (int64_t)(int32_t)v
: (int64_t)(uint32_t)v
);
2409 const char sch
= (n
< 0 ? '-' : 0);
2411 int base
= ufoImgGetU32(ufoBASEaddr
);
2412 if (base
< 2 || base
> 36) { snprintf(buf
, sizeof(buf
), "%s", "invalid-base"); return buf
; }
2414 if (bufpos
== 0) ufoFatal("number too long");
2415 char ch
= '0'+(char)(n
%base
);
2416 if (ch
> '9') ch
+= 7;
2418 } while ((n
/= base
) != 0);
2419 if (bufpos
!= 0 && sch
) buf
[--bufpos
] = sch
;
2427 int32_t v
= (int32_t)ufoPop();
2428 printf("%s ", ufoPrintNumber(v
, 1));
2434 uint32_t v
= ufoPop();
2435 printf("%s ", ufoPrintNumber(v
, 0));
2441 int32_t wdt
= (int32_t)ufoPop();
2442 int32_t v
= (int32_t)ufoPop();
2443 char *s
= ufoPrintNumber(v
, 1);
2444 int32_t slen
= (int32_t)strlen(s
);
2445 while (slen
< wdt
) { printf(" "); ++slen
; }
2452 int32_t wdt
= (int32_t)ufoPop();
2453 int32_t v
= (int32_t)ufoPop();
2454 char *s
= ufoPrintNumber(v
, 0);
2455 int32_t slen
= (int32_t)strlen(s
);
2456 while (slen
< wdt
) { printf(" "); ++slen
; }
2461 // ////////////////////////////////////////////////////////////////////////// //
2467 const uint32_t a
= ufoPop();
2474 const uint32_t b
= ufoPop();
2475 const uint32_t a
= ufoPop();
2482 const uint32_t b
= ufoPop();
2483 const uint32_t a
= ufoPop();
2490 const int32_t b
= (int32_t)ufoPop();
2491 const int32_t a
= (int32_t)ufoPop();
2492 ufoPush((uint32_t)(a
*b
));
2498 const uint32_t b
= ufoPop();
2499 const uint32_t a
= ufoPop();
2500 ufoPush((uint32_t)(a
*b
));
2506 const int32_t b
= (int32_t)ufoPop();
2507 const int32_t a
= (int32_t)ufoPop();
2508 if (b
== 0) ufoFatal("UFO division by zero");
2509 ufoPush((uint32_t)(a
/b
));
2515 const uint32_t b
= ufoPop();
2516 const uint32_t a
= ufoPop();
2517 if (b
== 0) ufoFatal("UFO division by zero");
2518 ufoPush((uint32_t)(a
/b
));
2524 const int32_t b
= (int32_t)ufoPop();
2525 const int32_t a
= (int32_t)ufoPop();
2526 if (b
== 0) ufoFatal("UFO division by zero");
2527 ufoPush((uint32_t)(a
%b
));
2533 const uint32_t b
= ufoPop();
2534 const uint32_t a
= ufoPop();
2535 if (b
== 0) ufoFatal("UFO division by zero");
2536 ufoPush((uint32_t)(a
%b
));
2540 // ( a b -- a/b, a%b )
2542 const int32_t b
= (int32_t)ufoPop();
2543 const int32_t a
= (int32_t)ufoPop();
2544 if (b
== 0) ufoFatal("UFO division by zero");
2545 ufoPush((uint32_t)(a
/b
));
2546 ufoPush((uint32_t)(a
%b
));
2550 // ( a b -- a/b, a%b )
2552 const uint32_t b
= ufoPop();
2553 const uint32_t a
= ufoPop();
2554 if (b
== 0) ufoFatal("UFO division by zero");
2555 ufoPush((uint32_t)(a
/b
));
2556 ufoPush((uint32_t)(a
%b
));
2560 // ////////////////////////////////////////////////////////////////////////// //
2566 const int32_t b
= (int32_t)ufoPop();
2567 const int32_t a
= (int32_t)ufoPop();
2574 const int32_t b
= (int32_t)ufoPop();
2575 const int32_t a
= (int32_t)ufoPop();
2582 const int32_t b
= (int32_t)ufoPop();
2583 const int32_t a
= (int32_t)ufoPop();
2584 ufoPushBool(a
<= b
);
2590 const int32_t b
= (int32_t)ufoPop();
2591 const int32_t a
= (int32_t)ufoPop();
2592 ufoPushBool(a
>= b
);
2598 const uint32_t b
= ufoPop();
2599 const uint32_t a
= ufoPop();
2606 const uint32_t b
= ufoPop();
2607 const uint32_t a
= ufoPop();
2614 const uint32_t b
= ufoPop();
2615 const uint32_t a
= ufoPop();
2616 ufoPushBool(a
<= b
);
2622 const uint32_t b
= ufoPop();
2623 const uint32_t a
= ufoPop();
2624 ufoPushBool(a
>= b
);
2630 const uint32_t b
= ufoPop();
2631 const uint32_t a
= ufoPop();
2632 ufoPushBool(a
== b
);
2638 const uint32_t b
= ufoPop();
2639 const uint32_t a
= ufoPop();
2640 ufoPushBool(a
!= b
);
2644 // ( value a b -- value>=a&&value<b )
2646 const int32_t b
= (int32_t)ufoPop();
2647 const int32_t a
= (int32_t)ufoPop();
2648 const int32_t value
= (int32_t)ufoPop();
2649 ufoPushBool(value
>= a
&& value
< b
);
2653 // ( value a b -- value>=a&&value<b )
2655 const uint32_t b
= ufoPop();
2656 const uint32_t a
= ufoPop();
2657 const uint32_t value
= ufoPop();
2658 ufoPushBool(value
>= a
&& value
< b
);
2662 // ( value a b -- value>=a&&value<=b )
2665 const uint32_t b
= ufoPop();
2666 const uint32_t a
= ufoPop();
2667 const uint32_t value
= ufoPop();
2668 ufoPushBool(value
>= a
&& value
<= b
);
2674 const uint32_t a
= ufoPop();
2681 const uint32_t a
= ufoPop();
2688 const uint32_t b
= ufoPop();
2689 const uint32_t a
= ufoPop();
2690 ufoPushBool(a
&& b
);
2696 const uint32_t b
= ufoPop();
2697 const uint32_t a
= ufoPop();
2698 ufoPushBool(a
|| b
);
2704 const uint32_t b
= ufoPop();
2705 const uint32_t a
= ufoPop();
2712 const uint32_t b
= ufoPop();
2713 const uint32_t a
= ufoPop();
2720 const uint32_t b
= ufoPop();
2721 const uint32_t a
= ufoPop();
2728 const uint32_t a
= ufoPop();
2732 UFWORD(ONEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+1u); }
2733 UFWORD(ONEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-1u); }
2734 UFWORD(TWOPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+2u); }
2735 UFWORD(TWOMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-2u); }
2736 UFWORD(THREEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+3u); }
2737 UFWORD(THREEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-3u); }
2738 UFWORD(FOURPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+4u); }
2739 UFWORD(FOURMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-4u); }
2740 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
*2u); }
2741 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
/2u); }
2743 UFWORD(LSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
<<c
); ufoPush(n
); }
2744 UFWORD(RSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
>>c
); ufoPush(n
); }
2748 // ////////////////////////////////////////////////////////////////////////// //
2754 if (ufoIsCompiling()) {
2755 ufoCompileLiteral(ufoPop());
2760 // ( addr count -- addr count )
2761 UFWORD(STR_UNESCAPE
) {
2762 uint32_t count
= (int32_t)ufoPop();
2763 const uint32_t addr
= ufoPeek();
2764 const uint32_t eaddr
= addr
+ count
;
2765 uint32_t caddr
= addr
;
2766 uint32_t daddr
= addr
;
2767 while (caddr
!= eaddr
) {
2768 uint8_t ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2769 if (ch
== '\\' && caddr
!= eaddr
) {
2770 ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2772 case 'r': ch
= '\r'; break;
2773 case 'n': ch
= '\n'; break;
2774 case 't': ch
= '\t'; break;
2775 case 'e': ch
= '\x1b'; break;
2776 case '`': ch
= '"'; break; // special escape to insert double-quoted
2777 case '"': ch
= '"'; break;
2778 case '\'': ch
= '\''; break;
2779 case '\\': ch
= '\\'; break;
2781 if (eaddr
- daddr
>= 1) {
2782 const int dg0
= digitInBase((char)(ufoImgGetU8(caddr
+ 1)), 16);
2783 if (dg0
< 0) ufoFatal("invalid hex string escape");
2784 if (eaddr
- daddr
>= 2) {
2785 const int dg1
= digitInBase((char)(ufoImgGetU8(caddr
+ 2)), 16);
2786 if (dg1
< 0) ufoFatal("invalid hex string escape");
2787 ch
= (uint8_t)(dg0
* 16 + dg1
);
2794 ufoFatal("invalid hex string escape");
2797 default: ufoFatal("invalid string escape");
2800 if (caddr
!= daddr
) ufoImgPutU32(daddr
, ch
);
2803 if (daddr
< eaddr
) ufoImgPutU32(daddr
, 0);
2804 ufoPush(daddr
- addr
);
2808 // I:( addr count -- addr count )
2809 // R:( -- addr count )
2810 // C:( addr count -- )
2811 // addr *MUST* be HERE+1
2812 UFWORD(STRLITERAL
) {
2813 UFCALL(STR_UNESCAPE
);
2814 if (ufoIsCompiling()) {
2815 uint32_t count
= ufoPop();
2816 uint32_t addr
= ufoPop();
2818 if (count
> 0xffffU
) ufoFatal("UFO string too long");
2819 if (addr
- 1u != ufoImageUsed
) {
2820 ufoFatal("invalid call to UFO word 'STRLITERAL'");
2822 ufoImgPutU32(addr
- 1u, count
);
2823 ufoImageUsed
+= count
+ 1u;
2829 // ( -- addr count )
2831 if (ufoIsCompiling()) ufoCompileCompilerWord("(\")");
2832 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2835 if (ufoIsInterpreting()) {
2837 uint32_t dest
= ufoPadAddr();
2838 uint32_t count
= ufoPop();
2839 uint32_t src
= ufoPop();
2840 if (dest
>= src
&& dest
<= src
+ count
) ufoFatal("something's wrong!");
2841 if (count
> 1022) ufoFatal("UFO string too long");
2842 ufoImgPutU32(dest
, count
);
2843 for (uint32_t n
= 0; n
< count
; ++n
) ufoImgPutU32(dest
+ n
+ 1, ufoImgGetU32(src
+ n
));
2844 ufoImgPutU32(dest
+ count
+ 1, 0);
2849 ufoFatal("string literal expected");
2856 if (ufoIsCompiling()) ufoCompileCompilerWord("(.\")");
2857 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2860 if (ufoIsInterpreting()) {
2864 ufoFatal("string literal expected");
2869 // ////////////////////////////////////////////////////////////////////////// //
2873 //==========================================================================
2875 // ufoGetInCharAutoLineAdvance
2877 //==========================================================================
2878 static uint8_t ufoGetInCharAutoLineAdvance (void) {
2881 ch
= ufoGetInChar();
2882 if (ch
== 0) ufoLoadNextLine(0);
2889 UFWORD(COMMENTEOL
) {
2890 // just skip the whole line
2891 while (ufoGetInChar() != 0) {}
2895 UFWORD(COMMENTPAREN
) {
2897 do { ch
= ufoGetInCharAutoLineAdvance(); } while (ch
!= ')');
2900 // "(*" multiline comment
2902 uint32_t prevch
= 0, ch
= 0;
2905 ch
= ufoGetInCharAutoLineAdvance();
2906 } while (prevch
!= '*' || ch
!= ')');
2909 // "((" multiline comment
2910 UFWORD(COMMENTML_NESTED
) {
2912 uint32_t prevch
= 0, ch
= 0;
2915 ch
= ufoGetInCharAutoLineAdvance();
2916 if (prevch
== '(' && ch
== '(') { ch
= 0; level
+= 1; }
2917 else if (prevch
== ')' && ch
== ')') { ch
= 0; level
-= 1; }
2918 } while (level
!= 0);
2922 // NFIND ( addr count -- cfa TRUE | 0 )
2925 const uint32_t count
= ufoPop();
2926 const uint32_t addr
= ufoPop();
2927 UForthWord
*fw
= ufoNFind(addr
, count
);
2929 ufoPush(fw
->cfaidx
);
2937 // convert number from addrl+1
2938 // returns address of the first inconvertible char
2939 // (XNUMBER) ( addr count -- num TRUE / FALSE )
2941 uint32_t count
= ufoPop();
2942 uint32_t addr
= ufoPop();
2945 int xbase
= (int)ufoImgGetU8(ufoBASEaddr
);
2947 // special-based numbers
2948 if (count
>= 3 && ufoImgGetU8(addr
) == '0') {
2949 switch (ufoImgGetU8(addr
+ 1)) {
2950 case 'x': case 'X': base
= 16; break;
2951 case 'o': case 'O': base
= 8; break;
2952 case 'b': case 'B': base
= 2; break;
2953 case 'd': case 'D': base
= 10; break;
2956 if (base
) { addr
+= 2; count
-= 2; }
2957 } else if (count
>= 2 && ufoImgGetU8(addr
) == '$') {
2959 addr
+= 1; count
-= 1;
2960 } else if (count
>= 2 && ufoImgGetU8(addr
) == '#') {
2962 addr
+= 1; count
-= 1;
2963 } else if (count
>= 2 && ufoImgGetU8(addr
) == '%') {
2965 addr
+= 1; count
-= 1;
2966 } else if (count
>= 3 && ufoImgGetU8(addr
) == '&') {
2967 switch (ufoImgGetU8(addr
+ 1)) {
2968 case 'h': case 'H': base
= 16; break;
2969 case 'o': case 'O': base
= 8; break;
2970 case 'b': case 'B': base
= 2; break;
2971 case 'd': case 'D': base
= 10; break;
2974 if (base
) { addr
+= 2; count
-= 2; }
2975 } else if (xbase
< 12 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'B') {
2978 } else if (xbase
< 18 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'H') {
2981 } else if (xbase
< 25 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'O') {
2988 if (!base
) base
= xbase
;
2990 if (count
== 0 || base
< 1 || base
> 36) {
2995 while (count
!= 0) {
2996 const uint32_t ch
= ufoImgGetU8(addr
);
2998 const int dig
= digitInBase((char)ch
, (int)base
);
3000 uint32_t nc
= n
* (uint32_t)base
+ (uint32_t)dig
;
3004 addr
+= 1; count
-= 1;
3021 UFCALL(PARSE_NAME
); // ( addr count )
3025 // end of input buffer; read next line
3026 #ifdef UFO_DEBUG_INLCUDE
3027 printf("*** NEW LINE ***\n");
3029 ufoLoadNextLine(1); // cross includes
3031 #ifdef UFO_DEBUG_INLCUDE
3032 printf("WORD: %u %u [", addr
, len
);
3033 ufoPush(addr
); ufoPush(len
); UFCALL(XTYPE
); printf("]"); UFCALL(CR
);
3040 // HACK: allow access to locals from code blocks
3041 // HACK: this will break badly if we'll pass such code blocks outside of the word
3042 if (len
> 1 && len
< 128 &&
3043 ufoInColon
> 0 && ufoIsCompiling() && ufoLocals
!= NULL
&&
3044 ufoImgGetU8(addr
) == ':')
3046 static char name
[257];
3048 for (uint32_t f
= 0; f
< len
; f
+= 1) name
[f
] = ufoImgGetU8(addr
+ f
);
3050 UForthLocRecord
*loc
= ufoFindLocal(name
, &wantStore
);
3053 snprintf(lwordn
, sizeof(lwordn
), "(LOCAL%c-%u)",
3054 (wantStore
? '!' : '@'), loc
->lidx
);
3055 UForthWord
*lfw
= ufoFindWordCompiler(lwordn
);
3057 ufoCompileWordCFA(lfw
);
3062 ufoCompileCompilerWord("(LOCAL!)");
3064 ufoCompileCompilerWord("(LOCAL@)");
3071 // find in dictionary
3072 ufoPush(addr
); ufoPush(len
);
3073 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3075 // word found, compile/execute
3076 UForthWord
*fw
= UFO_GET_NATIVE_CFA(ufoPop());
3077 if (!UFW_IS_IMM(fw
) && ufoIsCompiling()) {
3079 ufoCompileWordCFA(fw
);
3082 ufoExecuteNativeWordInVM(fw
);
3085 // word not found, try to parse a number
3087 if (ufoImgGetU8(addr
) == '-') { neg
= -1; ++addr
; --len
; }
3088 else if (ufoImgGetU8(addr
) == '+') { neg
= 1; ++addr
; --len
; }
3089 ufoPush(addr
); // address
3090 ufoPush(len
); // address
3092 // check if parsed successfully
3095 uint32_t n
= ufoPop();
3096 if (neg
< 0) n
= (~n
)+1u;
3100 // something wicked this way comes
3101 if (neg
) { --addr
; ++len
; }
3102 UFCALL(SPACE
); ufoPush(addr
); ufoPush(len
); UFCALL(XTYPE
);
3103 printf(" -- wut?\n"); ufoLastEmitWasCR
= 1;
3104 ufoFatal("unknown word");
3111 // ////////////////////////////////////////////////////////////////////////// //
3112 // image space allocation
3115 // ( size -- startaddr )
3116 // this cannot "deallot" memory
3118 uint32_t sz
= (int32_t)ufoPop();
3119 if (sz
>= 1024*1024*64) ufoFatal("cannot allot %u bytes", sz
);
3120 ufoImgEnsureSize(ufoImageUsed
+ sz
);
3121 ufoPush(ufoImageUsed
);
3133 // ////////////////////////////////////////////////////////////////////////// //
3134 // more compiler words
3138 ;; compile (0branch)
3149 // (BRANCH-ADDR!) ( destaddr addr -- )
3150 // write "branch to destaddr" address to addr
3151 UFWORD(PAR_BRANCH_ADDR_SET
) {
3152 uint32_t addr
= ufoPop();
3153 uint32_t dest
= ufoPop();
3154 ufoImgPutU32(addr
, dest
);
3157 // (BRANCH-ADDR@) ( addr -- dest )
3158 // read branch address
3159 UFWORD(PAR_BRANCH_ADDR_GET
) {
3160 uint32_t addr
= ufoPop();
3161 ufoPush(ufoImgGetU32(addr
));
3164 // (MARK-J>) ( -- addr )
3165 // reserve room for branch address, return addr suitable for "(RESOLVE-J>)"
3166 UFWORD(PAR_MARK_JFORWARD
) {
3168 ufoImgEmitU32(0); // 0 ,
3171 // (RESOLVE-J>) ( addr -- )
3172 // compile "forward jump" from address to HERE
3173 // addr is the result of "(MARK-J>)"
3174 UFWORD(PAR_RESOLVE_JFORWARD
) {
3177 UFCALL(PAR_BRANCH_ADDR_SET
);
3180 // (<J-MARK) ( -- addr )
3181 // return addr suitable for "(<J-RESOLVE)"
3182 UFWORD(PAR_MARK_JBACKWARD
) {
3186 // (<J-RESOLVE) ( addr -- )
3187 // patch "forward jump" address to HERE
3188 // addr is the result of "(<J-MARK)"
3189 UFWORD(PAR_RESOLVE_JBACKWARD
) {
3192 UFCALL(PAR_BRANCH_ADDR_SET
);
3198 if (ufoIsCompiling()) ufoFatal("expecting execution mode");
3203 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3208 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3209 if (ufoInColon
!= 1) ufoFatal("expecting colon compilation");
3213 UFWORD(QNOT_IN_COLON
) {
3214 if (ufoIsCompiling()) ufoFatal("expecting interpretation mode");
3215 if (ufoInColon
!= 0) ufoFatal("unexpected colon compilation");
3219 // ( ocond cond -- )
3221 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3222 const uint32_t cond
= ufoPop();
3223 const uint32_t ocond
= ufoPop();
3224 if (cond
!= ocond
) ufoFatal("unbalanced structured code");
3228 UFWORD(COMPILE_IMM
) {
3229 if (ufoIsInterpreting()) ufoFatal("cannot call `COMPILE` from interpreter");
3232 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3234 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3235 ufoCompileLiteral(cfa
);
3236 ufoCompileForthWord(",");
3238 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3239 printf(" -- wut?"); UFCALL(CR
);
3240 ufoFatal("unknown word");
3243 ufoFatal("word name expected");
3248 UFWORD(XCOMPILE_IMM
) {
3249 if (ufoIsInterpreting()) ufoFatal("cannot call `[COMPILE]` from interpreter");
3252 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3254 UForthWord
*fw
= UFO_GET_NATIVE_CFA(ufoPop());
3255 ufoCompileWordCFA(fw
);
3257 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3258 printf(" -- wut?"); UFCALL(CR
);
3259 ufoFatal("unknown word");
3262 ufoFatal("word name expected");
3270 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3272 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3273 if (ufoIsCompiling()) {
3274 ufoCompileLiteral(cfa
);
3279 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3280 printf(" -- wut?"); UFCALL(CR
);
3281 ufoFatal("unknown word");
3284 ufoFatal("word name expected");
3289 UFWORD(XTICKPFA_IMM
) {
3292 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3294 uint32_t cfa
= ufoPop();
3295 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3296 if (ufoIsCompiling()) {
3297 ufoCompileLiteral(fw
->pfa
);
3302 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3303 printf(" -- wut?"); UFCALL(CR
);
3304 ufoFatal("unknown word");
3307 ufoFatal("word name expected");
3317 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3319 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3322 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3323 printf(" -- wut?"); UFCALL(CR
);
3324 ufoFatal("unknown word");
3327 ufoFatal("word name expected");
3332 UFWORD(TICKPFA_IMM
) {
3336 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3338 uint32_t cfa
= ufoPop();
3339 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3342 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3343 printf(" -- wut?"); UFCALL(CR
);
3344 ufoFatal("unknown word");
3347 ufoFatal("word name expected");
3355 ufoImgEmitU32(ufoPop());
3360 // calculate the forward branch offset from addr to HERE and put it into the addr
3363 const uint32_t here
= ufoPop();
3364 const uint32_t addr
= ufoPop();
3365 ufoImgPutU32(addr
, here
);
3369 // ////////////////////////////////////////////////////////////////////////// //
3372 static int ufoIsLocalsEnter (UForthWord
*ww
) {
3374 if (ww
!= NULL
&& ww
->pfa
+ 1 < ufoImageUsed
) {
3375 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3376 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3377 res
= (w
== fw
->cfaidx
);
3383 //==========================================================================
3387 //==========================================================================
3388 static uint32_t ufoPrepareEnter (UForthWord
*ww
) {
3390 if (!ufoIsCompiling()) ufoFatal("compile mode expected");
3391 if (ufoInColon
!= 1) ufoFatal("must be in a word definition");
3392 if (ww
->cfa
!= NULL
) ufoFatal("wutafuck?");
3393 if (ww
->pfa
== ufoImageUsed
) {
3394 ufoCompileCompilerWord("(L-ENTER)");
3397 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3398 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3399 if (w
!= fw
->cfaidx
) ufoFatal("arg/local definition must be the first word");
3400 res
= ufoImgGetU32(ww
->pfa
+ 1);
3406 //==========================================================================
3410 //==========================================================================
3411 UFO_FORCE_INLINE
void ufoUpdateEnter (UForthWord
*ww
, uint32_t val
) {
3412 ufoImgPutU32(ww
->pfa
+ 1, val
);
3419 if (ufoRP
< ufoRPTop
) ufoFatal("return stack undeflow in (EXIT)");
3420 ufoStopVM
= (ufoRP
== ufoRPTop
);
3425 UFWORD(PAR_LENTER
) {
3426 // low byte of loccount is total number of locals
3427 // higt byte is the number of args
3428 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 1;
3429 uint32_t acount
= (lcount
>> 8)&0xff;
3431 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3432 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3433 ufoFatal("out of locals stack");
3436 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3437 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3438 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3439 ufoLBP
= newbp
; ufoLP
+= lcount
;
3442 while (newbp
!= ufoLBP
) {
3443 ufoLStack
[newbp
] = ufoPop();
3449 UFWORD(PAR_LLEAVE
) {
3450 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3451 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3453 ufoLBP
= ufoLStack
[ufoLBP
];
3458 if (ufoIsInterpreting()) ufoFatal("EXIT in interpreter?");
3459 if (ufoInColon
== 1) {
3460 if (ufoColonWord
->cfa
!= NULL
) ufoFatal("invalid EXIT");
3461 if (ufoIsLocalsEnter(ufoColonWord
)) ufoCompileCompilerWord("(L-LEAVE)");
3463 ufoCompileCompilerWord("(EXIT)");
3470 ufoCompileCompilerWord("(0BRANCH)");
3473 ufoPush(UFO_QPAIRS_IF
);
3479 ufoCompileCompilerWord("(TBRANCH)");
3482 ufoPush(UFO_QPAIRS_IF
);
3488 ufoPush(UFO_QPAIRS_IF
);
3496 ufoPush(UFO_QPAIRS_IF
);
3498 ufoCompileCompilerWord("(BRANCH)");
3502 ufoPush(UFO_QPAIRS_IF
);
3504 ufoPush(UFO_QPAIRS_IF
);
3511 ufoCompileCompilerWord("(DO)");
3513 ufoPush(UFO_QPAIRS_DO
);
3519 ufoPush(UFO_QPAIRS_DO
);
3521 ufoCompileCompilerWord("(LOOP)");
3528 ufoPush(UFO_QPAIRS_DO
);
3530 ufoCompileCompilerWord("(+LOOP)");
3539 ufoPush(UFO_QPAIRS_BEGIN
);
3542 static void ufoCommonUntil (const char *bword
) {
3545 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3549 ufoPush(UFO_QPAIRS_BEGIN
);
3553 // first is begin addr
3554 ufoCompileCompilerWord(bword
);
3557 // then jumps to the end
3558 while (ufoPeek() != ~0U) { UFCALL(COMP_FWD
); }
3564 UFWORD(UNTIL
) { ufoCommonUntil("(0BRANCH)"); }
3567 UFWORD(NOT_UNTIL
) { ufoCommonUntil("(TBRANCH)"); }
3570 UFWORD(AGAIN
) { ufoCommonUntil("(BRANCH)"); }
3572 static void ufoCommonWhile (int normal
) {
3575 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3579 ufoPush(UFO_QPAIRS_BEGIN
);
3584 ufoCompileCompilerWord(normal
? "(0BRANCH)" : "(TBRANCH)");
3588 ufoPush(UFO_QPAIRS_WHILE
);
3592 UFWORD(WHILE
) { ufoCommonWhile(1); }
3595 UFWORD(NOT_WHILE
) { ufoCommonWhile(0); }
3598 //==========================================================================
3602 //==========================================================================
3603 static void ufoXOF (const char *cmpwname
, int doswap
) {
3605 ufoPush(UFO_QPAIRS_CASE
);
3607 ufoCompileForthWord("OVER");
3608 if (doswap
) ufoCompileForthWord("SWAP");
3609 ufoCompileForthWord(cmpwname
);
3610 ufoCompileCompilerWord("(0BRANCH)");
3614 ufoCompileForthWord("DROP");
3615 ufoPush(UFO_QPAIRS_OF
);
3622 ufoPush(ufoCSP
); ufoCSP
= ufoSP
; //CSP @ !CSP
3623 ufoPush(UFO_QPAIRS_CASE
);
3639 ufoPush(UFO_QPAIRS_OF
);
3641 ufoCompileCompilerWord("(BRANCH)");
3646 ufoPush(UFO_QPAIRS_IF
);
3648 ufoPush(UFO_QPAIRS_CASE
);
3654 ufoPush(UFO_QPAIRS_CASE
);
3656 ufoPush(UFO_QPAIRS_OTHER
);
3662 if (ufoPeek() != UFO_QPAIRS_OTHER
) {
3663 ufoPush(UFO_QPAIRS_CASE
);
3665 ufoCompileForthWord("DROP");
3669 //fprintf(stderr, "SP=%u; csp=%u\n", ufoSP, ufoCSP);
3670 if (ufoSP
< ufoCSP
) ufoFatal("ENDCASE compiler error");
3671 while (ufoSP
> ufoCSP
) {
3672 ufoPush(UFO_QPAIRS_IF
);
3675 ufoCSP
= ufoPop(); //CSP !
3679 // ////////////////////////////////////////////////////////////////////////// //
3680 // define Forth words
3682 //==========================================================================
3686 //==========================================================================
3687 static UForthWord
*ufoRegisterWord (const char *wname
, void (*cfa
) (UForthWord
*self
),
3690 if (!wname
) wname
= "";
3691 if (strlen(wname
) > UFO_MAX_WORD_LENGTH
) ufoFatal("too long word name '%s'", wname
);
3692 UForthWord
*fw
= ufoFindWord(wname
);
3694 if (UFW_IS_PROT(fw
)) {
3695 ufoFatal("cannot redefine protected word '%s'", wname
);
3697 printf("redefined word '%s'.\n", wname
); ufoLastEmitWasCR
= 1;
3699 fw
= calloc(1, sizeof(UForthWord
));
3700 fw
->name
= strdup(wname
);
3701 fw
->namelen
= (uint32_t)strlen(fw
->name
);
3702 #ifdef UFO_UPPERCASE_DICT_WORDS
3703 for (char *s
= fw
->name
; *s
; ++s
) *s
= toUpper(*s
);
3706 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3708 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3709 fw
->pfastart
= ufoImageUsed
;
3711 ufoLinkWordToDict(fw
);
3712 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3713 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3714 //fprintf(stderr, "***NEW WORD #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
3719 //==========================================================================
3721 // ufoCreateNamelessForthWord
3723 //==========================================================================
3724 static UForthWord
*ufoCreateNamelessForthWord (void) {
3725 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
3726 fw
->name
= strdup("(nameless-word)");
3727 fw
->namelen
= 0; // it has no name
3728 fw
->cfa
= &ufoDoForth
;
3729 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3730 fw
->flags
= UFW_FLAG_PROTECTED
| UFW_FLAG_HIDDEN
;
3731 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3732 fw
->pfastart
= ufoImageUsed
;
3734 ufoLinkWordToDict(fw
);
3735 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3736 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3741 //==========================================================================
3745 //==========================================================================
3746 static UForthWord
*doNativeCreate (void) {
3747 ufoParseNameToTempBuf();
3748 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3749 fw
->pfa
= ufoImageUsed
;
3750 fw
->pfastart
= ufoImageUsed
;
3757 // either native, or ZX, depending of the current mode
3759 if (ufoIsCompiling()) ufoFatal("already compiling");
3760 if (ufoInColon
!= 0) ufoFatal("invalid ':' usage");
3761 ufoWipeLocRecords();
3763 UForthWord
*fw
= doNativeCreate();
3764 fw
->cfa
= NULL
; // for now
3766 ufoSetStateCompile();
3767 //fprintf(stderr, "compiling native <%s>\n", wname);
3768 // always remember old mode
3769 ufoPush(0xdeadbeefU
); // just a flag
3774 UFWORD(VOCABULARY
) {
3775 ufoParseNameToTempBuf();
3776 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3777 fw
->pfa
= 0xffffffffU
;
3778 ufoCreateVocabData(fw
);
3781 // NESTED-VOCABULARY name
3782 UFWORD(NESTED_VOCABULARY
) {
3783 uint32_t prev
= ufoLastVoc
;
3784 UForthWord
*voc
= UFO_GET_CFAPROC(prev
);
3785 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("'NESTED_VOCABULARY' internal error");
3786 ufoParseNameToTempBuf();
3787 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3788 fw
->pfa
= 0xffffffffU
;
3789 ufoCreateVocabData(fw
);
3790 ufoLinkVocab(fw
, voc
);
3800 if (ufoVSP
== UFO_VOCSTACK_SIZE
) ufoFatal("vocabulary stack overflow");
3801 ufoVocStack
[ufoVSP
] = ufoImgGetU32(ufoAddrContext
);
3807 if (ufoVSP
== 0) ufoFatal("vocabulary stack underflow");
3809 ufoImgPutU32(ufoAddrContext
, ufoVocStack
[ufoVSP
]);
3813 UFWORD(DEFINITIONS
) {
3814 ufoImgPutU32(ufoAddrCurrent
, ufoImgGetU32(ufoAddrContext
));
3815 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3821 ufoParseNameToTempBuf();
3822 UForthWord
*fw
= ufoAlwaysWord(ufoTempCharBuf
);
3823 if (!UFO_VALID_VOC_FW(fw
)) ufoFatal("word '%s' is not a vocabulary", ufoTempCharBuf
);
3824 ufoPush(fw
->cfaidx
);
3829 UFWORD(VOC_PUBLIC_MODE
) {
3830 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3834 UFWORD(VOC_HIDDEN_MODE
) {
3835 ufoDefaultVocFlags
|= UFW_FLAG_VOC_HIDDEN
;
3838 // <PROTECTED-WORDS>
3839 UFWORD(VOC_PROTECTED_MODE
) {
3840 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
3843 // <UNPROTECTED-WORDS>
3844 UFWORD(VOC_UNPROTECTED_MODE
) {
3845 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
3851 if (ufoIsCompiling()) ufoFatal("already compiling");
3852 if (ufoInColon
!= 0) ufoFatal("invalid 'CREATE' usage");
3853 ufoWipeLocRecords();
3854 ufoInColon
= 0x00010000;
3855 UForthWord
*fw
= doNativeCreate();
3856 fw
->cfa
= &ufoDoVariable
; // for now
3857 //fw->flags |= UFW_FLAG_HIDDEN;
3862 UFWORD(CREATE_SEMI
) {
3863 if (ufoIsCompiling()) ufoFatal("already compiling");
3864 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'CREATE;' usage");
3865 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'CREATE;' usage");
3866 ufoLastDefinedNativeWord
= ufoColonWord
;
3867 ufoWipeLocRecords();
3869 ufoColonWord
->pfaend
= ufoImageUsed
;
3870 //ufoColonWord->flags &= ~UFW_FLAG_HIDDEN;
3875 if (ufoIsCompiling()) ufoFatal("already compiling");
3876 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'DOES>' usage");
3877 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'DOES>' usage");
3878 ufoColonWord
->cfa
= NULL
; // for semicolon
3879 ufoColonWord
->pfa
= ufoImageUsed
;
3880 ufoWipeLocRecords();
3882 // this is for semicolon
3884 ufoPush(0xdead0badU
); // just a flag
3885 ufoSetStateCompile();
3891 if (ufoIsInterpreting()) ufoFatal("not compiling");
3892 if (ufoInColon
!= 1) ufoFatal("where's my colon?");
3893 ufoLastDefinedNativeWord
= NULL
;
3896 const uint32_t guard
= ufoPop();
3897 if (guard
!= 0xdeadbeefU
&& guard
!= 0xdead0badU
) {
3898 ufoFatal("UFO finishing word primary magic imbalance!");
3900 // compile finishing word
3901 if (ufoColonWord
== NULL
|| ufoColonWord
->cfa
!= NULL
) ufoFatal("UFO ';' without ':'");
3902 ufo_assert(ufoColonWord
->pfa
!= 0xffffffffU
);
3903 ufoColonWord
->cfa
= &ufoDoForth
;
3904 if (ufoIsLocalsEnter(ufoColonWord
)) {
3905 ufoCompileCompilerWord("(L-LEAVE)");
3907 ufoCompileCompilerWord("(EXIT)");
3908 //ufoDecompileForth(ufoForthDict);
3909 ufoLastDefinedNativeWord
= ufoColonWord
;
3910 ufoColonWord
->pfaend
= ufoImageUsed
;
3911 ufoSetStateInterpret();
3912 // stack must be empty
3913 //if (ufoSP) ufoFatal("UFO finishing word primary imbalance!");
3915 ufoWipeLocRecords();
3917 ufoColonWord
= NULL
;
3919 // call optimiser if there is any
3920 UForthWord
*ofw
= ufoFindWordCompiler("OPTIMISE-WORD");
3921 if (ofw
&& ofw
!= ufoLastDefinedNativeWord
) {
3922 //if (ufoMode == UFO_MODE_ZX) fprintf(stderr, "**********000: #%04X\n", disp);
3923 ufoPush(ufoLastDefinedNativeWord
->cfaidx
);
3924 ufoExecuteNativeWordInVM(ofw
);
3930 if (ufoLastDefinedNativeWord
) {
3931 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_IMMEDIATE
;
3933 ufoFatal("wtf in `IMMEDIATE`");
3938 UFWORD(PAR_PROTECTED
) {
3939 if (ufoLastDefinedNativeWord
) {
3940 // we cannot unprotect the word
3941 ufoLastDefinedNativeWord
->flags
|= UFW_FLAG_PROTECTED
;
3943 ufoFatal("wtf in `(PROTECTED)`");
3948 UFWORD(PAR_HIDDEN
) {
3949 if (ufoLastDefinedNativeWord
) {
3950 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_VOC_HIDDEN
;
3952 ufoFatal("wtf in `(HIDDEN)`");
3956 UFWORD(RECURSE_IMM
) {
3958 //if (!ufoGetState()) ufoFatal("not compiling");
3959 if (ufoLastDefinedNativeWord
) {
3960 ufoImgEmitU32(ufoLastDefinedNativeWord
->cfaidx
);
3962 ufoFatal("wtf in `RECURSE`");
3967 //==========================================================================
3969 // ufoArgsLocalsCommon
3971 //==========================================================================
3972 static void ufoArgsLocalsCommon (uint32_t increment
) {
3973 uint32_t eidx
= ufoPrepareEnter(ufoColonWord
);
3974 uint32_t ch
= ufoGetInChar();
3979 if (dpos
>= UFO_MAX_WORD_LENGTH
- 1 || dpos
>= (uint32_t)sizeof(ufoTempCharBuf
)) {
3980 ufoFatal("name too long");
3982 ufoTempCharBuf
[dpos
] = (char)ch
; dpos
+= 1;
3983 ch
= ufoGetInChar();
3985 ufoTempCharBuf
[dpos
] = 0;
3986 if ((eidx
&0xffU
) > 127) ufoFatal("too many locals at '%s'", ufoTempCharBuf
);
3988 ufoNewLocal(ufoTempCharBuf
);
3990 ch
= ufoGetInChar();
3993 ufoUpdateEnter(ufoColonWord
, eidx
);
3996 // args: name name...
3997 UFWORD(ARGS_IMM
) { ufoArgsLocalsCommon(0x0101); } // increment high byte too
3998 // locals: name name...
3999 UFWORD(LOCALS_IMM
) { ufoArgsLocalsCommon(1); }
4002 //==========================================================================
4006 //==========================================================================
4007 UFO_FORCE_INLINE
void ufoLoadLocal (uint32_t lidx
) {
4008 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
4009 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
4010 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
4014 //==========================================================================
4018 //==========================================================================
4019 UFO_FORCE_INLINE
void ufoStoreLocal (uint32_t lidx
) {
4020 uint32_t value
= ufoPop();
4021 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
4022 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
4023 ufoLStack
[ufoLBP
+ lidx
] = value
;
4029 UFWORD(LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
4031 // (LOCAL@-1) .. (LOCAL@-7)
4032 UFWORD(LOCAL_LOAD_1
) { ufoLoadLocal(1); }
4033 UFWORD(LOCAL_LOAD_2
) { ufoLoadLocal(2); }
4034 UFWORD(LOCAL_LOAD_3
) { ufoLoadLocal(3); }
4035 UFWORD(LOCAL_LOAD_4
) { ufoLoadLocal(4); }
4036 UFWORD(LOCAL_LOAD_5
) { ufoLoadLocal(5); }
4037 UFWORD(LOCAL_LOAD_6
) { ufoLoadLocal(6); }
4038 UFWORD(LOCAL_LOAD_7
) { ufoLoadLocal(7); }
4039 UFWORD(LOCAL_LOAD_8
) { ufoLoadLocal(8); }
4040 UFWORD(LOCAL_LOAD_9
) { ufoLoadLocal(9); }
4041 UFWORD(LOCAL_LOAD_10
) { ufoLoadLocal(10); }
4042 UFWORD(LOCAL_LOAD_11
) { ufoLoadLocal(11); }
4043 UFWORD(LOCAL_LOAD_12
) { ufoLoadLocal(12); }
4044 UFWORD(LOCAL_LOAD_13
) { ufoLoadLocal(13); }
4045 UFWORD(LOCAL_LOAD_14
) { ufoLoadLocal(14); }
4046 UFWORD(LOCAL_LOAD_15
) { ufoLoadLocal(15); }
4047 UFWORD(LOCAL_LOAD_16
) { ufoLoadLocal(16); }
4051 UFWORD(LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
4053 // (LOCAL!-1) .. (LOCAL!-7)
4054 UFWORD(LOCAL_STORE_1
) { ufoStoreLocal(1); }
4055 UFWORD(LOCAL_STORE_2
) { ufoStoreLocal(2); }
4056 UFWORD(LOCAL_STORE_3
) { ufoStoreLocal(3); }
4057 UFWORD(LOCAL_STORE_4
) { ufoStoreLocal(4); }
4058 UFWORD(LOCAL_STORE_5
) { ufoStoreLocal(5); }
4059 UFWORD(LOCAL_STORE_6
) { ufoStoreLocal(6); }
4060 UFWORD(LOCAL_STORE_7
) { ufoStoreLocal(7); }
4061 UFWORD(LOCAL_STORE_8
) { ufoStoreLocal(8); }
4062 UFWORD(LOCAL_STORE_9
) { ufoStoreLocal(9); }
4063 UFWORD(LOCAL_STORE_10
) { ufoStoreLocal(10); }
4064 UFWORD(LOCAL_STORE_11
) { ufoStoreLocal(11); }
4065 UFWORD(LOCAL_STORE_12
) { ufoStoreLocal(12); }
4066 UFWORD(LOCAL_STORE_13
) { ufoStoreLocal(13); }
4067 UFWORD(LOCAL_STORE_14
) { ufoStoreLocal(14); }
4068 UFWORD(LOCAL_STORE_15
) { ufoStoreLocal(15); }
4069 UFWORD(LOCAL_STORE_16
) { ufoStoreLocal(16); }
4072 // ////////////////////////////////////////////////////////////////////////// //
4075 // (CODEBLOCK) ( -- )
4076 UFWORD(CODEBLOCK_PAR
) {
4077 // current IP is "jump over" destination
4078 // next IP is cfaidx
4079 ufoPush(ufoImgGetU32(ufoIP
+1u)); // push cfa
4080 ufoIP
= ufoImgGetU32(ufoIP
); // branch over the code block
4083 // [: -- start code block
4084 UFWORD(CODEBLOCK_START_IMM
) {
4085 if (ufoInColon
<= 0) ufoInColon
-= 1; else ufoInColon
+= 1;
4087 ufoCompileCompilerWord("(CODEBLOCK)");
4089 ufoImgEmitU32(0); // jump over
4090 // create nameless word
4091 UForthWord
*fw
= ufoCreateNamelessForthWord();
4092 ufoImgEmitU32(fw
->cfaidx
); // cfaidx
4093 fw
->pfa
= ufoImageUsed
;
4094 fw
->pfastart
= ufoImageUsed
;
4096 ufoPush(UFO_QPAIRS_CBLOCK
);
4099 // ;] -- end code block
4100 UFWORD(CODEBLOCK_END_IMM
) {
4101 if (ufoInColon
== 0 || ufoInColon
== 1) ufoFatal("end of code block without start");
4102 if (ufoInColon
< 0) ufoInColon
+= 1; else ufoInColon
-= 1;
4103 if (!UFW_IS_HID(ufoForthDict
) || ufoForthDict
->cfa
!= &ufoDoForth
) {
4104 ufoFatal("invalid code block!");
4107 ufoPush(UFO_QPAIRS_CBLOCK
);
4109 ufoCompileCompilerWord("(EXIT)"); // finish code block
4111 ufoForthDict
->pfaend
= ufoImageUsed
;
4115 // ////////////////////////////////////////////////////////////////////////// //
4122 // COMPILER:CREATE-NAMELESS
4124 // create nameless forth word
4125 UFWORD(CREATE_NAMELESS
) {
4127 if (ufoInColon
!= 0) ufoFatal("nameless in colon/codeblock? what a funny idea");
4128 UForthWord
*fw
= ufoCreateNamelessForthWord();
4130 ufoImgEmitU32(fw
->cfaidx
); // cfaidx
4131 fw
->pfa
= ufoImageUsed
;
4132 fw
->pfastart
= ufoImageUsed
;
4134 ufoLastDefinedNativeWord
= NULL
;
4137 ufoPush(fw
->cfaidx
);
4138 //ufoPush(0xdeadbeefU);
4142 // ////////////////////////////////////////////////////////////////////////// //
4143 static void ufoDoVariable (UForthWord
*self
) { ufoPush(self
->pfa
); }
4144 static void ufoDoValue (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4145 static void ufoDoConst (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4147 static void ufoDoDefer (UForthWord
*self
) {
4148 const uint32_t cfaidx
= ufoImgGetU32(self
->pfastart
);
4149 ufoExecCFAIdx(cfaidx
);
4154 UForthWord
*fvar
= doNativeCreate();
4155 fvar
->cfa
= &ufoDoValue
;
4156 fvar
->pfa
= ufoImageUsed
;
4158 ufoImgEmitU32(ufoPop());
4159 fvar
->pfaend
= ufoImageUsed
;
4163 UFWORD(VAR_NOALLOT
) {
4164 UForthWord
*fvar
= doNativeCreate();
4165 fvar
->cfa
= &ufoDoVariable
;
4166 fvar
->pfa
= ufoImageUsed
;
4167 // no variable value yet
4172 UForthWord
*fvar
= doNativeCreate();
4173 fvar
->cfa
= &ufoDoVariable
;
4174 fvar
->pfa
= ufoImageUsed
;
4176 ufoImgEmitU32(ufoPop());
4177 fvar
->pfaend
= ufoImageUsed
;
4182 UForthWord
*fvar
= doNativeCreate();
4183 fvar
->cfa
= &ufoDoConst
;
4184 fvar
->pfa
= ufoImageUsed
;
4186 ufoImgEmitU32(ufoPop());
4187 fvar
->pfaend
= ufoImageUsed
;
4192 UForthWord
*fvar
= doNativeCreate();
4193 fvar
->cfa
= &ufoDoDefer
;
4194 fvar
->pfa
= ufoImageUsed
;
4196 ufoImgEmitU32(ufoPop());
4197 fvar
->pfaend
= ufoImageUsed
;
4201 // ( addr count -- here size )
4202 // load data file from disk, put it to HERE
4203 // file is unpacked to cells (i.e. each byte will occupy one cell)
4204 // the usual "!" and "*" modifiers are ok
4205 UFWORD(LOAD_DATA_FILE
) {
4206 ufoPopStrLitToTempBuf();
4207 const char *orgname
= ufoTempCharBuf
;
4208 int system
= 0, softinclude
= 0;
4209 while (*orgname
!= 0) {
4210 if (*orgname
== '!') {
4211 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4213 } else if (*orgname
== '?') {
4214 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4221 } while (*orgname
> 0 && *orgname
<= 32);
4223 if (*orgname
== 0) ufoFatal("empty file name");
4225 const uint32_t addr
= ufoPop();
4227 char *fname
= ufoCreateIncludeName(orgname
, system
, ufoLastIncPath
);
4228 FILE *fl
= fopen(fname
, "rb");
4230 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4234 ssize_t res
= fread(&bt
, 1, 1, fl
);
4236 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4238 ufoImgPutU8(addr
+ count
, bt
); count
+= 1;
4247 // ZX-LOAD-DATA-FILE
4248 // ( addr count -- )
4249 // load data file from disk, put it to org, advance org
4250 // the usual "!" and "*" modifiers are ok
4251 UFWORD(ZX_LOAD_DATA_FILE
) {
4252 ufoPopStrLitToTempBuf();
4253 const char *orgname
= ufoTempCharBuf
;
4254 int system
= 0, softinclude
= 0;
4255 while (*orgname
!= 0) {
4256 if (*orgname
== '!') {
4257 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4259 } else if (*orgname
== '?') {
4260 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4267 } while (*orgname
> 0 && *orgname
<= 32);
4269 if (*orgname
== 0) ufoFatal("empty file name");
4270 char *fname
= ufoCreateIncludeName(orgname
, system
, ufoLastIncPath
);
4271 FILE *fl
= fopen(fname
, "rb");
4273 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4277 ssize_t res
= fread(&bt
, 1, 1, fl
);
4279 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4291 UForthWord
*fw
= ufoNTWordAddrCount();
4292 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4293 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4295 if (ufoIsCompiling()) {
4298 ufoCompileLiteral(fw
->pfa
);
4299 ufoCompileForthWord("!");
4302 ufoImgPutU32(fw
->pfa
, ufoPop());
4307 // ( value addr count -- )
4309 UForthWord
*fw
= ufoNTWordAddrCount();
4310 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4311 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4313 if (ufoIsCompiling()) {
4316 ufoCompileLiteral(fw
->pfa
);
4317 ufoCompileForthWord("!");
4320 ufoImgPutU32(fw
->pfa
, ufoPop());
4327 uint32_t cfa
= ufoPop();
4328 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
4335 // cfa of the last compiled word
4336 UFWORD(LATEST_CFA
) {
4337 if (ufoLastDefinedNativeWord
!= NULL
) {
4338 ufoPush(ufoLastDefinedNativeWord
->cfaidx
);
4347 // cfa of the current compiling word
4348 UFWORD(COLON_WORD
) {
4350 if (ufoColonWord
== NULL
) ufoFatal("not compiling a word");
4351 ufoPush(ufoColonWord
->cfaidx
);
4355 // ////////////////////////////////////////////////////////////////////////// //
4358 UFWORD(LSQBRACKET_IMM
) {
4359 ufoSetStateInterpret();
4363 UFWORD(RSQBRACKET
) {
4364 ufoSetStateCompile();
4368 // ////////////////////////////////////////////////////////////////////////// //
4372 // ( addr count -- flag )
4373 UFWORD(UR_HAS_LABELQ
) {
4374 ufoPopStrLitToTempBuf();
4375 ufoPushBool(ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
);
4379 // ( addr count -- type )
4381 UFWORD(UR_GET_LABELQ_TYPE
) {
4382 ufoPopStrLitToTempBuf();
4383 ufoPush(ufoZXGetLabelType(ufoTempCharBuf
));
4387 // ( addr count -- value )
4388 // fatals when the label is not found
4389 UFWORD(UR_GET_LABELQ
) {
4390 ufoPopStrLitToTempBuf();
4391 ufoPush((uint32_t)ufoZXGetLabelValue(ufoTempCharBuf
));
4399 //==========================================================================
4403 //==========================================================================
4404 static uint32_t zxLabelIter (const char *name
, int type
, int value
, void *udata
) {
4405 LIterInfo
*nfo
= (LIterInfo
*)udata
;
4406 uint32_t addr
= ufoPutTempStrLiteral(name
);
4407 uint32_t count
= ufoImgGetU32(addr
++);
4410 ufoExecCFAIdxInVM(nfo
->cfaidx
);
4416 // EXECUTEs cfa, returns final res
4417 // cfa: ( addr count -- stopflag )
4418 // i.e. return non-zero from cfa to stop
4419 // res is the result of the last called cfa
4420 UFWORD(UR_FOREACH_LABEL
) {
4422 nfo
.cfaidx
= ufoPop();
4423 uint32_t res
= ufoZXForeachLabel(&zxLabelIter
, &nfo
);
4424 ufoPush((uint32_t)res
);
4428 //==========================================================================
4430 // urw_set_typed_label
4432 // ( value addr count -- )
4434 //==========================================================================
4435 static void urw_set_typed_label (UForthWord
*self
, int type
) {
4436 ufoPopStrLitToTempBuf();
4437 const char *name
= ufoTempCharBuf
;
4438 int32_t val
= (int32_t)ufoPop();
4439 ufoZXSetLabelValue(name
, type
, val
);
4444 // ( value addr count -- )
4445 // create/overwrite an "assign" label
4446 UFWORD(UR_SET_LABEL_VAR
) { urw_set_typed_label(self
, UFO_ZX_LABEL_VAR
); }
4449 // ( value addr count -- )
4450 UFWORD(UR_SET_LABEL_EQU
) { urw_set_typed_label(self
, UFO_ZX_LABEL_EQU
); }
4452 // UR-SET-LABEL-CODE
4453 // ( value addr count -- )
4454 UFWORD(UR_SET_LABEL_CODE
) { urw_set_typed_label(self
, UFO_ZX_LABEL_CODE
); }
4456 // UR-SET-LABEL-STOFS
4457 // ( value addr count -- )
4458 UFWORD(UR_SET_LABEL_STOFS
) { urw_set_typed_label(self
, UFO_ZX_LABEL_STOFS
); }
4460 // UR-SET-LABEL-DATA
4461 // ( value addr count -- )
4462 UFWORD(UR_SET_LABEL_DATA
) { urw_set_typed_label(self
, UFO_ZX_LABEL_DATA
); }
4465 //==========================================================================
4467 // urw_declare_typed_label
4469 //==========================================================================
4470 static void urw_declare_typed_label (UForthWord
*self
, int type
) {
4472 ufoParseNameToTempBuf();
4473 if (ufoTempCharBuf
[0] == 0) ufoFatal("label name expected");
4474 const char *name
= ufoTempCharBuf
;
4475 ufoZXSetLabelValue(name
, type
, ufoZXGetOrg());
4478 // $LABEL-DATA: name
4479 UFWORD(DLR_LABEL_DATA_IMM
) { urw_declare_typed_label(self
, UFO_ZX_LABEL_DATA
); }
4480 // $LABEL-CODE: name
4481 UFWORD(DLR_LABEL_CODE_IMM
) { urw_declare_typed_label(self
, UFO_ZX_LABEL_CODE
); }
4487 ufoPush(ufoZXGetPass());
4493 ufoPush(ufoZXGetOrg());
4498 UFWORD(UR_GETDISP
) {
4499 ufoPush(ufoZXGetDisp());
4505 ufoPush(ufoZXGetEnt());
4512 const uint32_t addr
= ufoPop();
4518 // doesn't change ORG
4519 UFWORD(UR_SETDISP
) {
4520 const uint32_t addr
= ufoPop();
4527 const uint32_t addr
= ufoPop();
4532 // ////////////////////////////////////////////////////////////////////////// //
4533 // conditional compilation
4535 typedef struct UForthCondDefine_t UForthCondDefine
;
4536 struct UForthCondDefine_t
{
4538 UForthCondDefine
*prev
;
4541 static UForthCondDefine
*ufoCondDefines
= NULL
;
4544 //==========================================================================
4546 // ufoClearCondDefines
4548 //==========================================================================
4549 static void ufoClearCondDefines (void) {
4550 while (ufoCondDefines
) {
4551 UForthCondDefine
*df
= ufoCondDefines
;
4552 ufoCondDefines
= df
->prev
;
4553 if (df
->name
) free(df
->name
);
4559 //==========================================================================
4563 //==========================================================================
4564 static int ufoHasCondDefine (const char *name
) {
4565 if (!name
|| !name
[0]) return 0;
4566 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4567 if (strcmp(dd
->name
, name
) == 0) return 1;
4573 //==========================================================================
4577 //==========================================================================
4578 static void ufoAddCondDefine (const char *name
) {
4579 if (!name
|| !name
[0]) return;
4580 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4581 if (strcmp(dd
->name
, name
) == 0) return;
4583 UForthCondDefine
*dd
= malloc(sizeof(UForthCondDefine
));
4584 dd
->name
= strdup(name
);
4585 dd
->prev
= ufoCondDefines
;
4586 ufoCondDefines
= dd
;
4590 //==========================================================================
4592 // ufoRemoveCondDefine
4594 //==========================================================================
4595 static void ufoRemoveCondDefine (const char *name
) {
4596 if (!name
|| !name
[0]) return;
4597 UForthCondDefine
*pp
= NULL
;
4598 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4599 if (strcmp(dd
->name
, name
) == 0) {
4600 if (pp
) pp
->prev
= dd
->prev
; else ufoCondDefines
= dd
->prev
;
4610 //==========================================================================
4612 // ufoParseConditionTerm
4614 //==========================================================================
4615 static int ufoParseConditionTerm (int doskip
) {
4617 if (strEquCI(ufoTempCharBuf
, "DEFINED")) {
4618 ufoParseNameToTempBuf();
4619 res
= (doskip
? 0 : ufoHasCondDefine(ufoTempCharBuf
));
4620 } else if (strEquCI(ufoTempCharBuf
, "UNDEFINED")) {
4621 ufoParseNameToTempBuf();
4622 res
= (doskip
? 0 : !ufoHasCondDefine(ufoTempCharBuf
));
4623 } else if (strEquCI(ufoTempCharBuf
, "HAS-WORD")) {
4624 ufoParseNameToTempBuf();
4625 res
= (doskip
? 0 : !!ufoFindWord(ufoTempCharBuf
));
4626 } else if (strEquCI(ufoTempCharBuf
, "NO-WORD")) {
4627 ufoParseNameToTempBuf();
4628 res
= (doskip
? 0 : !ufoFindWord(ufoTempCharBuf
));
4629 } else if (strEquCI(ufoTempCharBuf
, "HAS-LABEL")) {
4630 ufoParseNameToTempBuf();
4631 res
= (doskip
? 0 : ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
);
4632 } else if (strEquCI(ufoTempCharBuf
, "NO-LABEL")) {
4633 ufoParseNameToTempBuf();
4634 res
= (doskip
? 0 : ufoZXGetLabelType(ufoTempCharBuf
) <= UFO_ZX_LABEL_UNKNOWN
);
4635 } else if (strEquCI(ufoTempCharBuf
, "PASS0")) {
4636 res
= (doskip
? 0 : (ufoZXGetPass() == 0));
4637 } else if (strEquCI(ufoTempCharBuf
, "PASS1")) {
4638 res
= (doskip
? 0 : (ufoZXGetPass() == 1));
4644 if (ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
) {
4645 res
= ufoZXGetLabelValue(ufoTempCharBuf
);
4649 res
= !!strtol(ufoTempCharBuf
, &e
, 10);
4650 if (*e
) ufoFatal("undefined label '%s'", ufoTempCharBuf
);
4654 ufoParseNameToTempBufEmptyOk();
4659 //==========================================================================
4661 // ufoParseConditionUnary
4663 //==========================================================================
4664 static int ufoParseConditionUnary (int doskip
) {
4666 if (strEquCI(ufoTempCharBuf
, "(")) {
4667 res
= ufoParseConditionExpr(doskip
);
4668 if (!strEquCI(ufoTempCharBuf
, ")")) ufoFatal("unbalanced parens in $IF condition");
4669 } else if (strEquCI(ufoTempCharBuf
, "NOT")) {
4670 ufoParseNameToTempBuf();
4671 res
= !ufoParseConditionUnary(doskip
);
4673 res
= ufoParseConditionTerm(doskip
);
4679 //==========================================================================
4681 // ufoParseConditionAnd
4683 //==========================================================================
4684 static int ufoParseConditionAnd (int doskip
) {
4685 int res
= ufoParseConditionUnary(doskip
);
4686 doskip
= (res
== 0);
4687 while (strEquCI(ufoTempCharBuf
, "AND") || strEquCI(ufoTempCharBuf
, "&&")) {
4688 ufoParseNameToTempBuf();
4689 int r2
= ufoParseConditionUnary(doskip
);
4692 doskip
= (res
== 0);
4699 //==========================================================================
4701 // ufoParseConditionOr
4703 //==========================================================================
4704 static int ufoParseConditionOr (int doskip
) {
4705 int res
= ufoParseConditionAnd(doskip
);
4706 doskip
= (res
!= 0);
4707 while (strEquCI(ufoTempCharBuf
, "OR") || strEquCI(ufoTempCharBuf
, "||")) {
4708 ufoParseNameToTempBuf();
4709 int r2
= ufoParseConditionAnd(doskip
);
4712 doskip
= (res
!= 0);
4719 //==========================================================================
4721 // ufoParseConditionExpr
4723 //==========================================================================
4724 static int ufoParseConditionExpr (int doskip
) {
4725 return ufoParseConditionOr(doskip
);
4729 //==========================================================================
4731 // ufoSkipConditionals
4733 //==========================================================================
4734 static void ufoSkipConditionals (int toelse
) {
4735 const int oldCondStLine
= ufoCondStLine
;
4736 ufoCondStLine
= ufoInFileLine
;
4737 int iflevel
= 0, done
= 0;
4740 ufoParseNameToTempBufEmptyOk();
4741 if (ufoTempCharBuf
[0]) {
4742 // nested conditionals
4743 if (strEquCI(ufoTempCharBuf
, "$IF")) {
4745 } else if (strEquCI(ufoTempCharBuf
, "$ENDIF")) {
4746 // in nested ifs, look only for $ENDIF
4750 // it doesn't matter which part we're skipping, it ends here anyway
4753 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELSE")) {
4754 // if we're skipping "true" part, go on
4758 // we're skipping "false" part, there should be no else
4759 ufoFatal("unexpected $ELSE, skipping from line %d", ufoCondStLine
);
4762 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELIF")) {
4763 // if we're skipping "true" part, go on
4765 // process the conditional
4766 int res
= ufoParseConditionExpr(0);
4767 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4768 // either resume normal execution, or keep searching for $ELSE
4774 // we're skipping "false" part, there should be no else
4775 ufoFatal("unexpected $ELIFxx, skipping from line %d", ufoCondStLine
);
4779 } while (done
== 0);
4780 ufo_assert(iflevel
== 0);
4782 ufoCondStLine
= oldCondStLine
;
4786 //==========================================================================
4788 // ufoProcessConditional
4790 //==========================================================================
4791 static void ufoProcessConditional (void) {
4792 ufoParseNameToTempBuf();
4793 int res
= ufoParseConditionExpr(0);
4794 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4796 ufoSkipConditionals(1); // skip to $ELSE
4804 // ( count addr -- )
4805 UFWORD(ASM_WARNING
) {
4806 ufoPopStrLitToTempBuf();
4807 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4808 fprintf(stdout
, "*** USER WARNING ");
4809 if (ufoInFile
!= NULL
) {
4810 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4812 fprintf(stdout
, "somewhere in time: ");
4814 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4819 // ( count addr -- )
4821 ufoPopStrLitToTempBuf();
4822 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4823 fprintf(stdout
, "*** USER ERROR ");
4824 if (ufoInFile
!= NULL
) {
4825 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4827 fprintf(stdout
, "somewhere in time: ");
4829 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4835 UFWORD(DLR_DEFINE
) {
4836 ufoParseNameToTempBuf();
4837 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4838 ufoAddCondDefine(ufoTempCharBuf
);
4843 ufoParseNameToTempBuf();
4844 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4845 ufoRemoveCondDefine(ufoTempCharBuf
);
4848 // these words can be encoundered only when we're done with some $IF, so skip to $ENDIF
4850 UFWORD(DLR_ELSE_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELSE without $IF"); ufoSkipConditionals(0); }
4852 UFWORD(DLR_ELIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELIF without $IF"); --ufoInCondIf
; ufoSkipConditionals(0); }
4854 UFWORD(DLR_ENDIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ENDIF without $IF"); --ufoInCondIf
; }
4857 UFWORD(DLR_IF_IMM
) { ufoProcessConditional(); }
4861 // ( addr count -- )
4864 uint32_t count
= ufoPop();
4865 uint32_t addr
= ufoPop();
4867 int system
= 0, softinclude
= 0;
4870 while (count
!= 0) {
4871 ch
= ufoImgGetU8(addr
);
4873 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4875 } else if (ch
== '?') {
4876 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4882 addr
+= 1; count
-= 1;
4883 ch
= ufoImgGetU8(addr
);
4884 } while (ch
<= 32 && count
!= 0);
4888 if ((size_t)count
>= sizeof(fname
)) ufoFatal("include file name too long");
4890 while (count
!= 0) {
4891 fname
[dpos
] = (char)ufoImgGetU8(addr
); dpos
+= 1;
4892 addr
+= 1; count
-= 1;
4896 char *ffn
= ufoCreateIncludeName(fname
, system
, ufoLastIncPath
);
4897 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4899 if (softinclude
) { free(ffn
); return; }
4900 ufoFatal("INCLUDE: file '%s' not found", ffn
);
4905 ufoInFileName
= ffn
;
4906 setLastIncPath(ufoInFileName
);
4908 // trigger next line loading
4909 ufoSetTIB(0); ufoSetIN(0);
4914 //==========================================================================
4916 // ufoDollarIncludeCommon
4918 //==========================================================================
4919 static void ufoDollarIncludeCommon (const char *defname
) {
4922 int system
= 0, softinclude
= 0;
4924 int skipit
= (defname
!= NULL
&& ufoHasCondDefine(defname
));
4926 ch
= ufoGetInChar();
4927 while (ch
!= 0 && ch
!= '"' && ch
!= '<') {
4928 ch
= ufoGetInChar();
4931 if (ch
== 0) ufoFatal("quoted file name expected");
4933 if (ch
== '<') { system
= 1; qch
= '>'; } else qch
= '"';
4934 ch
= ufoGetInChar();
4936 if (ch
== 0) ufoFatal("properly quoted file name expected");
4938 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4940 } else if (ch
== '?') {
4941 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4947 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
!= qch
);
4952 while (ch
!= 0 && ch
!= qch
) {
4953 if ((size_t)dpos
>= sizeof(fname
)) ufoFatal("include file name too long");
4954 fname
[dpos
] = (char)ch
; dpos
+= 1;
4955 ch
= ufoGetInChar();
4958 // final parsing checks
4959 if (ch
== 0) ufoFatal("properly quoted file name expected");
4960 ch
= ufoGetInChar();
4962 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
<= 32);
4963 if (ch
!= 0) ufoFatal("unexpected extra text");
4966 if (defname
!= NULL
) ufoAddCondDefine(defname
);
4967 char *ffn
= ufoCreateIncludeName(fname
, system
, ufoLastIncPath
);
4968 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4970 if (softinclude
) { free(ffn
); return; }
4971 ufoFatal("$INCLUDE: file '%s' not found", ffn
);
4976 ufoInFileName
= ffn
;
4977 setLastIncPath(ufoInFileName
);
4980 // trigger next line loading
4981 ufoSetTIB(0); ufoSetIN(0);
4986 // $INCLUDE-ONCE define-guard filename
4987 UFWORD(DLR_INCLUDE_ONCE
) {
4988 ufoParseNameToTempBuf();
4989 ufoDollarIncludeCommon(ufoTempCharBuf
);
4992 // $INCLUDE filename
4993 UFWORD(DLR_INCLUDE
) {
4994 ufoDollarIncludeCommon(NULL
);
5000 UFWORD(DUMP_STACK
) {
5001 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5002 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
5003 for (uint32_t sp
= 0; sp
< ufoSP
; ++sp
) {
5004 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
5012 //fprintf(stderr, "***UFO STACK DEPTH: %u\n", ufoSP); for (uint32_t sp = 0; sp < ufoSP; ++sp) fprintf(stderr, " %4u: 0x%08x %d\n", sp, ufoDStack[sp], (int32_t)ufoDStack[sp]);
5013 ufoPopStrLitToTempBuf();
5014 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5015 ufoFatal("%s", ufoTempCharBuf
);
5019 // ( errflag addr count -- )
5021 const uint32_t count
= ufoPop();
5022 const uint32_t addr
= ufoPop();
5026 ufoPopStrLitToTempBuf();
5027 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5028 ufoFatal("%s", ufoTempCharBuf
);
5033 // ////////////////////////////////////////////////////////////////////////// //
5037 //==========================================================================
5039 // ufoSetForthOnlyDefs
5041 //==========================================================================
5042 static void ufoSetForthOnlyDefs (void) {
5043 ufoImgPutU32(ufoAddrCurrent
, ufoForthVocCFA
);
5044 ufoImgPutU32(ufoAddrContext
, ufoForthVocCFA
);
5048 //==========================================================================
5050 // ufoCreateVocSetOnlyDefs
5052 //==========================================================================
5053 static UForthWord
*ufoCreateVocSetOnlyDefs (const char *wname
, UForthWord
*parentvoc
) {
5054 UForthWord
*fw
= ufoRegisterWord(wname
, NULL
, ufoDefaultVocFlags
);
5055 fw
->pfa
= 0xffffffffU
;
5056 ufoCreateVocabData(fw
);
5058 ufoLinkVocab(fw
, parentvoc
);
5059 // and set as active
5060 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
5061 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
5066 //==========================================================================
5068 // ufoVocSetOnlyDefs
5070 //==========================================================================
5071 __attribute__((unused
)) static void ufoVocSetOnlyDefs (UForthWord
*fw
) {
5072 if (UFO_VALID_VOC_FW(fw
)) {
5073 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
5074 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
5076 ufoSetForthOnlyDefs();
5081 //==========================================================================
5085 //==========================================================================
5086 static void ufoDefine (const char *wname
) {
5087 UForthWord
*fw
= ufoRegisterWord(wname
, &ufoDoForth
, ufoDefaultVocFlags
);
5088 fw
->pfa
= ufoImageUsed
;
5089 fw
->pfastart
= ufoImageUsed
;
5091 //fprintf(stderr, "***DEFINING #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
5092 ufoSetStateCompile();
5096 //==========================================================================
5100 //==========================================================================
5101 static void ufoDefineDone (void) {
5102 ufoLastDefinedNativeWord
= NULL
;
5104 if (ufoSP
) ufoFatal("UFO finishing word primary imbalance!");
5105 //if (!ufoForthDict || ufoForthDict->cfa) ufoFatal("UFO ';' without ':'");
5106 ufo_assert(ufoForthDict
->pfa
!= 0xffffffffU
);
5107 ufoForthDict
->cfa
= &ufoDoForth
;
5108 ufoForthDict
->pfaend
= ufoImageUsed
;
5109 ufoCompileCompilerWord("(EXIT)");
5110 //ufoDecompileForth(ufoForthDict);
5111 ufoLastDefinedNativeWord
= ufoForthDict
;
5112 ufoSetStateInterpret();
5116 //==========================================================================
5120 //==========================================================================
5121 static void ufoNumber (uint32_t v
) {
5122 ufoCompileCompilerWord("LIT");
5127 //==========================================================================
5131 //==========================================================================
5132 static void ufoCompile (const char *wname
) {
5133 UForthWord
*fw
= ufoFindWord(wname
);
5137 long v
= strtol(wname
, &end
, 0);
5138 if (end
== wname
|| *end
) ufoFatal("UFO word '%s' not found", wname
);
5139 ufoNumber((uint32_t)v
);
5141 // compile/execute a word
5142 if (UFW_IS_IMM(fw
)) {
5143 ufoExecuteNativeWordInVM(fw
);
5145 ufoCompileWordCFA(fw
);
5151 //==========================================================================
5155 //==========================================================================
5156 static __attribute__((unused
)) void ufoString (const char *str
) {
5157 ufoCompileCompilerWord("(\")");
5159 size_t slen
= strlen(str
);
5160 if (slen
> 65535) ufoFatal("UFO string too long");
5161 ufoImgEmitU32((uint32_t)slen
);
5163 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5169 //==========================================================================
5173 //==========================================================================
5174 static __attribute__((unused
)) void ufoDotString (const char *str
) {
5175 ufoCompileCompilerWord("(.\")");
5177 size_t slen
= strlen(str
);
5178 if (slen
> 65535) ufoFatal("UFO string too long");
5179 ufoImgEmitU32((uint32_t)slen
);
5181 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5187 // ////////////////////////////////////////////////////////////////////////// //
5189 #include "urforth_dbg.c"
5193 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5195 ufoFatal("there is no UFO debug breakpoint support in windoze");
5197 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
5200 fprintf(stderr
, "WARNING: cannot start UFO debug session, because standard streams are not on TTY!\n");
5206 // ////////////////////////////////////////////////////////////////////////// //
5210 // ( vocid -- cfa / 0 )
5211 UFWORD(WORDS_ITER_NEW
) {
5212 uint32_t vocid
= ufoPop();
5213 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5214 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("WORDS-ITER-NEW expects a valid vocid");
5215 UForthWord
*fw
= voc
->latest
;
5216 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5217 uint32_t cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5222 // ( cfa -- cfa / 0 )
5223 // closes iterator on completion
5224 UFWORD(WORDS_ITER_PREV
) {
5225 uint32_t cfa
= ufoPop();
5226 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5227 if (fw
!= NULL
) fw
= fw
->prevVoc
;
5228 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5229 cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5234 // ( cfa -- addr count )
5235 // somewhere at PAD; invalid CFA returns empty string
5236 UFWORD(WORDS_ITER_NAME
) {
5237 uint32_t cfa
= ufoPop();
5238 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5239 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5240 uint32_t addr
= ufoPutTempStrLiteral(fw
->name
);
5241 uint32_t count
= ufoImgGetU32(addr
++);
5245 uint32_t dest
= ufoPadAddr();
5246 ufoImgPutU32(dest
, 0);
5247 ufoImgPutU32(dest
+1, 0);
5249 ufoPush(0u); // count
5254 // ( cfa -- pfa / 0 )
5255 UFWORD(WORDS_ITER_PFA
) {
5256 uint32_t cfa
= ufoPop();
5257 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5258 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5267 UFWORD(WORDS_ITER_IMMQ
) {
5268 uint32_t cfa
= ufoPop();
5269 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5270 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5271 ufoPushBool(UFW_IS_IMM(fw
));
5279 UFWORD(WORDS_ITER_PROTQ
) {
5280 uint32_t cfa
= ufoPop();
5281 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5282 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5283 ufoPushBool(UFW_IS_PROT(fw
));
5289 // WORDS-ITER-HIDDEN?
5291 UFWORD(WORDS_ITER_HIDDENQ
) {
5292 uint32_t cfa
= ufoPop();
5293 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5294 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5295 ufoPushBool(UFW_IS_VOC_HID(fw
));
5312 UFWORD(WORDS_ITER_TYPEQ
) {
5313 uint32_t cfa
= ufoPop();
5314 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5315 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5316 if (fw
->cfa
== &ufoDoForth
) ufoPush(fw
->pfa
== fw
->pfastart
? 2 : 7);
5317 else if (fw
->cfa
== &ufoDoVariable
) ufoPush(3);
5318 else if (fw
->cfa
== &ufoDoValue
) ufoPush(4);
5319 else if (fw
->cfa
== &ufoDoConst
) ufoPush(5);
5320 else if (fw
->cfa
== &ufoDoDefer
) ufoPush(6);
5321 else if (fw
->cfa
== &ufoDoVoc
) ufoPush(7);
5322 else ufoPush(1); // code
5330 // ( vocid cfa -- res )
5331 // EXECUTEs cfa, returns final res
5332 // cfa: ( wordcfa -- stopflag )
5333 // i.e. return non-zero from cfa to stop
5334 // res is the result of the last called cfa
5335 UFWORD(UFO_FOREACH_WORD
) {
5336 uint32_t cfaidx
= ufoPop();
5337 uint32_t vocid
= ufoPop();
5339 UForthWord
*fw
= NULL
;
5340 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5341 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("FOREACH-WORD expects a valid vocid");
5343 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5346 while (res
== 0 && fw
!= NULL
) {
5347 if (fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5348 ufoPush(fw
->cfaidx
);
5349 ufoExecCFAIdxInVM(cfaidx
);
5361 // EXECUTEs cfa, returns final res
5362 // cfa: ( vocid -- stopflag )
5363 // i.e. return non-zero from cfa to stop
5364 // res is the result of the last called cfa
5365 UFWORD(UFO_FOREACH_VOC
) {
5367 uint32_t cfaidx
= ufoPop();
5368 uint32_t vocid
= ufoLastVoc
;
5369 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5370 while (UFO_VALID_VOC_FW(voc
)) {
5371 if (!UFW_IS_HID(voc
)) {
5372 ufoPush(voc
->cfaidx
);
5373 ufoExecCFAIdxInVM(cfaidx
);
5376 vocid
= ufoImgGetU32(voc
->pfa
+ UFW_VOCAB_OFS_VOCLINK
);
5377 voc
= UFO_GET_CFAPROC(vocid
);
5383 // ////////////////////////////////////////////////////////////////////////// //
5387 UFWORD(DLR_END_FORTH
) {
5388 if (ufoMode
!= UFO_MODE_NATIVE
) ufoFatal("$END_FORTH in non-native mode");
5389 if (ufoIsCompiling()) ufoFatal("$END_FORTH: still compiling something");
5390 longjmp(ufoInlineQuitJP
, 1);
5394 //==========================================================================
5396 // ufoDecompileForth
5398 //==========================================================================
5399 static void ufoDecompileForthPart (uint32_t addr
, uint32_t endaddr
, int indent
) {
5400 while (addr
!= 0 && addr
< ufoImageUsed
&& addr
< endaddr
) {
5401 uint32_t cfaidx
= ufoImgGetU32(addr
);
5402 fprintf(stderr
, "%8u: ", addr
);
5403 for (int f
= 0; f
< indent
; f
+= 1) fputc(' ', stderr
);
5404 if ((cfaidx
& UFO_RS_CFA_BIT
) == 0) {
5405 fprintf(stderr
, "<bad-cfa>");
5408 cfaidx
&= UFO_RS_CFA_MASK
;
5409 if (cfaidx
>= ufoCFAsUsed
) {
5410 fprintf(stderr
, "<bad-cfa>");
5413 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
5414 fprintf(stderr
, "%s", fw
->name
);
5416 if (fw
->cfa
== UFCFA(BRANCH
) ||
5417 fw
->cfa
== UFCFA(0BRANCH
) ||
5418 fw
->cfa
== UFCFA(TBRANCH
) ||
5419 fw
->cfa
== UFCFA(LOOP_PAREN
) ||
5420 fw
->cfa
== UFCFA(PLOOP_PAREN
))
5422 uint32_t jaddr
= ufoImgGetU32(addr
++);
5423 fprintf(stderr
, " %u", jaddr
);
5424 } else if (fw
->cfa
== UFCFA(LIT
) || fw
->cfa
== UFCFA(PAR_LENTER
)) {
5425 uint32_t n
= ufoImgGetU32(addr
++);
5426 fprintf(stderr
, " %u", n
);
5427 } else if (fw
->cfa
== UFCFA(STRQ_PAREN
) || fw
->cfa
== UFCFA(STRDOTQ_PAREN
)) {
5428 uint32_t count
= ufoImgGetU32(addr
++);
5429 fprintf(stderr
, " cnt=%u; ~", count
);
5431 uint8_t ch
= ufoImgGetU32(addr
++)&0xffU
;
5432 if (ch
== '\r') fprintf(stderr
, "\\r");
5433 else if (ch
== '\n') fprintf(stderr
, "\\n");
5434 else if (ch
== '\t') fprintf(stderr
, "\\t");
5435 else if (ch
== '\\') fprintf(stderr
, "\\\\");
5436 else if (ch
== '"') fprintf(stderr
, "\\`");
5437 else if (ch
< 32 || ch
== 127) fprintf(stderr
, "\\x%02x", ch
);
5438 else fprintf(stderr
, "%c", (char)ch
);
5440 fprintf(stderr
, "~");
5441 } else if (fw
->cfa
== UFCFA(CODEBLOCK_PAR
)) {
5442 uint32_t jover
= ufoImgGetU32(addr
++);
5443 addr
+= 1; // skip cfa idx
5444 fputc('\n', stderr
);
5445 ufoDecompileForthPart(addr
, jover
, indent
+ 2);
5451 fputc('\n', stderr
);
5456 //==========================================================================
5458 // ufoDecompileForth
5460 //==========================================================================
5461 static void ufoDecompileForth (UForthWord
*fw
) {
5463 fprintf(stderr
, "====: %s", fw
->name
);
5464 if (fw
->cfa
== &ufoDoForth
) {
5465 if (fw
->pfa
!= fw
->pfastart
) {
5466 fprintf(stderr
, " -- DOES, data at %d", fw
->pfastart
);
5468 fputc('\n', stderr
);
5469 ufoDecompileForthPart(fw
->pfa
, fw
->pfaend
, 0);
5470 } else if (fw
->cfa
== ufoDoDefer
) {
5471 fprintf(stderr
, " -- DEFER\n");
5472 } else if (fw
->cfa
== ufoDoConst
) {
5473 fprintf(stderr
, " -- CONSTANT\n");
5474 } else if (fw
->cfa
== ufoDoValue
) {
5475 fprintf(stderr
, " -- VALUE\n");
5476 } else if (fw
->cfa
== ufoDoVariable
) {
5477 fprintf(stderr
, " -- VARIABLE\n");
5479 fprintf(stderr
, "----\n");
5483 // ( addr count -- )
5484 UFWORD(UFO_DECOMPILE_INTERNAL
) {
5485 UForthWord
*fw
= ufoNTWordAddrCount();
5486 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5487 ufoDecompileForth(fw
);
5491 //==========================================================================
5493 // ufoVocHashBucketStats
5495 //==========================================================================
5496 static void ufoVocHashBucketStats (UForthWord
*voc
) {
5497 if (UFO_VALID_VOC_FW(voc
)) {
5498 int used
= 0, min
= 0x7fffffff, max
= -1, wcount
= 0;
5499 for (unsigned f
= 0; f
< UFO_DICT_HASH_BUCKETS
; f
+= 1) {
5500 UForthWord
*fw
= voc
->buckets
[f
];
5504 while (fw
!= NULL
) { wcount
+= 1; total
+= 1; fw
= fw
->hlink
; }
5505 if (total
< min
) min
= total
;
5506 if (total
> max
) max
= total
;
5509 printf("VOCABULARY '%s': %d WORDS, BUCKETS USED: %d\n", voc
->name
, wcount
, used
);
5511 printf("MIN BUCKET: %d\n", min
);
5512 printf("MAX BUCKET: %d\n", max
);
5518 // (UFO-BUCKET-STATS)
5519 UFWORD(PAR_UFO_BUCKET_STATS
) {
5520 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5522 uint32_t vocid
= ufoLastVoc
;
5523 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5524 while (UFO_VALID_VOC_FW(voc
)) {
5525 ufoVocHashBucketStats(voc
);
5526 vocid
= ufoImgGetU32(voc
->pfa
+ UFW_VOCAB_OFS_VOCLINK
);
5527 voc
= UFO_GET_CFAPROC(vocid
);
5532 // ////////////////////////////////////////////////////////////////////////// //
5535 #define UFWORD(name_) ufoRegisterWord(""#name_, ufoWord_##name_, ufoDefaultVocFlags)
5536 #define UFWORDX(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, ufoDefaultVocFlags)
5538 #define UFWORD_IMM(name_) ufoRegisterWord(""#name_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5539 #define UFWORDX_IMM(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5542 #define UFC(wn_) ufoCompile(""#wn_);
5543 #define UFS(wn_) ufoString(""#wn_);
5544 #define UFDS(wn_) ufoDotString(""#wn_);
5545 #define UFN(wn_) ufoNumber(wn_);
5547 #define UFBEGIN UFCALL(BEGIN);
5548 #define UFAGAIN UFCALL(AGAIN);
5551 //==========================================================================
5555 //==========================================================================
5556 static void ufoDefineQuit (void) {
5557 ufoDefine("UFO-RUN-LOOP");
5566 //==========================================================================
5568 // ufoDefineConstant
5570 //==========================================================================
5571 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5572 UForthWord
*fw
= ufoRegisterWord(name
, &ufoDoConst
, ufoDefaultVocFlags
);
5573 fw
->pfa
= ufoImageUsed
;
5574 fw
->pfastart
= ufoImageUsed
;
5576 ufoImgEmitU32(value
);
5577 fw
->pfaend
= ufoImageUsed
;
5581 //==========================================================================
5585 //==========================================================================
5586 static void ufoDefineMisc (void) {
5587 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
5593 ufoNumber(16); UFC(BASE
); UFC(!);
5596 ufoDefine("DECIMAL");
5597 ufoNumber(10); UFC(BASE
); UFC(!);
5601 UFC(0) UFC(SWAP
) UFC(!)
5605 UFC(1) UFC(SWAP
) UFC(!)
5609 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(+) UFC(SWAP
) UFC(!)
5613 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(SWAP
) UFC(-) UFC(SWAP
) UFC(!)
5617 UFC(DUP
) UFC(@
) UFC(1+) UFC(SWAP
) UFC(!)
5621 UFC(DUP
) UFC(@
) UFC(2+) UFC(SWAP
) UFC(!)
5625 UFC(DUP
) UFC(@
) UFC(3+) UFC(SWAP
) UFC(!)
5629 UFC(DUP
) UFC(@
) UFC(4+) UFC(SWAP
) UFC(!)
5633 UFC(DUP
) UFC(@
) UFC(1-) UFC(SWAP
) UFC(!)
5637 UFC(DUP
) UFC(@
) UFC(2-) UFC(SWAP
) UFC(!)
5641 UFC(DUP
) UFC(@
) UFC(3-) UFC(SWAP
) UFC(!)
5645 UFC(DUP
) UFC(@
) UFC(4-) UFC(SWAP
) UFC(!)
5649 ufoNumber(0); UFC(=);
5653 ufoNumber(0); UFC(<>);
5657 ufoNumber(0); UFC(!=);
5661 ufoNumber(0); UFC(<);
5665 ufoNumber(0); UFC(>);
5669 ufoNumber(0); UFC(<=);
5673 ufoNumber(0); UFC(>=);
5677 ufoNumber(0); UFC(U
>);
5681 ufoNumber(1); UFC(=);
5685 ufoNumber(1); UFC(<>);
5689 ufoNumber(1); UFC(!=);
5693 ufoNumber(1); UFC(<);
5697 ufoNumber(1); UFC(>);
5701 ufoNumber(1); UFC(<=);
5705 ufoNumber(1); UFC(>=);
5709 ufoNumber(1); UFC(U
>);
5713 ufoNumber(1); UFC(U
<=);
5716 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
5720 //==========================================================================
5724 //==========================================================================
5725 static void ufoReset (void) {
5726 ufoWipeLocRecords();
5731 ufoSP
= 0; ufoRP
= 0;
5732 ufoLP
= 0; ufoLBP
= 0;
5736 ufoSetStateInterpret();
5738 ufoSetTIB(0); ufoSetIN(0);
5741 ufoColonWord
= NULL
;
5743 ufoDefaultVocFlags
= 0;
5745 ufoSetForthOnlyDefs();
5749 //==========================================================================
5753 //==========================================================================
5754 static void ufoInitCommon (void) {
5755 ufoForthDict
= NULL
;
5756 ufoColonWord
= NULL
;
5757 ufoLastVoc
= ~0U; ufoDefaultVocFlags
= 0;
5758 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
5760 ufoDStack
= calloc(UFO_DSTACK_SIZE
, sizeof(ufoDStack
[0]));
5761 ufoRStack
= calloc(UFO_RSTACK_SIZE
, sizeof(ufoRStack
[0]));
5762 ufoLStack
= calloc(UFO_LSTACK_SIZE
, sizeof(ufoLStack
[0]));
5763 ufoForthCFAs
= calloc(UFO_MAX_WORDS
, sizeof(ufoForthCFAs
[0]));
5764 // CFA 0 is reserved for FORTH vocabulary
5768 while (ufoImageUsed
<= ufoTIBAreaSize
) ufoImgEmitU32(0);
5771 ufoBASEaddr
= ufoImageUsed
;
5775 ufoSTATEaddr
= ufoImageUsed
;
5779 ufoAddrTIB
= ufoImageUsed
;
5783 ufoAddrIN
= ufoImageUsed
;
5787 ufoAddrContext
= ufoImageUsed
;
5791 ufoAddrCurrent
= ufoImageUsed
;
5794 ufoSetStateInterpret();
5796 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
5797 fw
->name
= strdup("FORTH");
5798 fw
->namelen
= (uint32_t)strlen(fw
->name
);
5800 FW_SET_CFAIDX(fw
, 0); // known thing
5801 fw
->flags
= UFW_FLAG_PROTECTED
;
5802 fw
->pfa
= 0xffffffffU
;
5803 ufoForthVocCFA
= fw
->cfaidx
;
5804 ufoForthCFAs
[0] = fw
; // for proper links
5805 ufoCreateVocabData(fw
);
5806 // set CURRENT and CONTEXT
5807 ufoSetForthOnlyDefs();
5809 ufoLinkWordToDict(fw
);
5811 ufoDefaultVocFlags
= UFW_FLAG_PROTECTED
;
5813 UForthWord
*vcomp
= ufoCreateVocSetOnlyDefs("COMPILER", NULL
);
5814 ufoCompSuppVocCFA
= vcomp
->cfaidx
;
5815 ufoSetForthOnlyDefs();
5817 ufoMacroVocCFA
= ufoCreateVocSetOnlyDefs("URASM-MACROS", NULL
)->cfaidx
;
5818 ufoSetForthOnlyDefs();
5820 UForthWord
*vstr
= ufoCreateVocSetOnlyDefs("STRING", NULL
);
5821 ufoSetForthOnlyDefs();
5824 // base low-level interpreter words
5825 ufoDefineConstant("FALSE", 0);
5826 ufoDefineConstant("TRUE", ufoTrueValue
);
5828 ufoDefineConstant("BL", 32);
5829 ufoDefineConstant("NL", 10);
5831 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
5832 UFWORDX("SP0!", SP0_PUT
);
5833 UFWORDX("RP0!", RP0_PUT
);
5838 UFWORDX("C@", CPEEK
);
5839 UFWORDX("C!", CPOKE
);
5840 UFWORDX("W@", WPEEK
);
5841 UFWORDX("W!", WPOKE
);
5842 UFWORDX("C,", CCOMMA
);
5843 UFWORDX(",", COMMA
);
5845 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
5846 ufoVocSetOnlyDefs(vcomp
);
5848 UFWORDX("(BRANCH)", BRANCH
);
5849 UFWORDX("(TBRANCH)", TBRANCH
);
5850 UFWORDX("(0BRANCH)", 0BRANCH
);
5851 UFWORDX("(DO)", DO_PAREN
);
5852 UFWORDX("(LOOP)", LOOP_PAREN
);
5853 UFWORDX("(+LOOP)", PLOOP_PAREN
);
5855 // low-level compiler words
5856 UFWORDX("STRLITERAL", STRLITERAL
);
5858 UFWORDX("(\")", STRQ_PAREN
);
5859 UFWORDX("(.\")", STRDOTQ_PAREN
);
5861 UFWORDX("(EXIT)", PAR_EXIT
);
5862 UFWORDX("(L-ENTER)", PAR_LENTER
);
5863 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
5865 UFWORDX("(BRANCH-ADDR!)", PAR_BRANCH_ADDR_SET
);
5866 UFWORDX("(BRANCH-ADDR@)", PAR_BRANCH_ADDR_GET
);
5867 UFWORDX("(MARK-J>)", PAR_MARK_JFORWARD
);
5868 UFWORDX("(RESOLVE-J>)", PAR_RESOLVE_JFORWARD
);
5869 UFWORDX("(<J-MARK)", PAR_MARK_JBACKWARD
);
5870 UFWORDX("(<J-RESOLVE)", PAR_RESOLVE_JBACKWARD
);
5873 UFWORDX("?EXEC", QEXEC
);
5874 UFWORDX("?COMP", QCOMP
);
5875 UFWORDX("?PAIRS", QPAIRS
);
5876 UFWORDX("COMP-BACK", COMP_BACK
);
5877 UFWORDX("COMP-FWD", COMP_FWD
);
5878 UFWORDX("?IN-COLON", QIN_COLON
);
5879 UFWORDX("?NOT-IN-COLON", QNOT_IN_COLON
);
5881 UFWORDX("(LOCAL@)", LOCAL_LOAD
);
5882 UFWORDX("(LOCAL!)", LOCAL_STORE
);
5884 UFWORDX("(LOCAL@-1)", LOCAL_LOAD_1
);
5885 UFWORDX("(LOCAL@-2)", LOCAL_LOAD_2
);
5886 UFWORDX("(LOCAL@-3)", LOCAL_LOAD_3
);
5887 UFWORDX("(LOCAL@-4)", LOCAL_LOAD_4
);
5888 UFWORDX("(LOCAL@-5)", LOCAL_LOAD_5
);
5889 UFWORDX("(LOCAL@-6)", LOCAL_LOAD_6
);
5890 UFWORDX("(LOCAL@-7)", LOCAL_LOAD_7
);
5891 UFWORDX("(LOCAL@-8)", LOCAL_LOAD_8
);
5892 UFWORDX("(LOCAL@-9)", LOCAL_LOAD_9
);
5893 UFWORDX("(LOCAL@-10)", LOCAL_LOAD_10
);
5894 UFWORDX("(LOCAL@-11)", LOCAL_LOAD_11
);
5895 UFWORDX("(LOCAL@-12)", LOCAL_LOAD_12
);
5896 UFWORDX("(LOCAL@-13)", LOCAL_LOAD_13
);
5897 UFWORDX("(LOCAL@-14)", LOCAL_LOAD_14
);
5898 UFWORDX("(LOCAL@-15)", LOCAL_LOAD_15
);
5899 UFWORDX("(LOCAL@-16)", LOCAL_LOAD_16
);
5901 UFWORDX("(LOCAL!-1)", LOCAL_STORE_1
);
5902 UFWORDX("(LOCAL!-2)", LOCAL_STORE_2
);
5903 UFWORDX("(LOCAL!-3)", LOCAL_STORE_3
);
5904 UFWORDX("(LOCAL!-4)", LOCAL_STORE_4
);
5905 UFWORDX("(LOCAL!-5)", LOCAL_STORE_5
);
5906 UFWORDX("(LOCAL!-6)", LOCAL_STORE_6
);
5907 UFWORDX("(LOCAL!-7)", LOCAL_STORE_7
);
5908 UFWORDX("(LOCAL!-8)", LOCAL_STORE_8
);
5909 UFWORDX("(LOCAL!-9)", LOCAL_STORE_9
);
5910 UFWORDX("(LOCAL!-10)", LOCAL_STORE_10
);
5911 UFWORDX("(LOCAL!-11)", LOCAL_STORE_11
);
5912 UFWORDX("(LOCAL!-12)", LOCAL_STORE_12
);
5913 UFWORDX("(LOCAL!-13)", LOCAL_STORE_13
);
5914 UFWORDX("(LOCAL!-14)", LOCAL_STORE_14
);
5915 UFWORDX("(LOCAL!-15)", LOCAL_STORE_15
);
5916 UFWORDX("(LOCAL!-16)", LOCAL_STORE_16
);
5918 UFWORDX("(CODEBLOCK)", CODEBLOCK_PAR
);
5920 UFWORDX("COLON-WORD", COLON_WORD
);
5922 UFWORDX("CREATE-NAMELESS", CREATE_NAMELESS
);
5924 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
5925 ufoSetForthOnlyDefs();
5928 UFWORDX_IMM("RECURSE", RECURSE_IMM
);
5932 UFWORDX("?DUP", QDUP
);
5933 UFWORDX("2DUP", DDUP
);
5935 UFWORDX("2DROP", DDROP
);
5937 UFWORDX("2SWAP", DSWAP
);
5939 UFWORDX("2OVER", DOVER
);
5950 UFWORDX(">R", DTOR
);
5951 UFWORDX("R>", RTOD
);
5952 UFWORDX("R@", RPEEK
);
5954 UFWORDX("CMOVE>", CMOVE_FWD
);
5955 UFWORDX("CMOVE", CMOVE_BACK
);
5956 UFWORDX("MOVE", MOVE
);
5957 UFWORDX("FILL", FILL
);
5959 ufoVocSetOnlyDefs(vstr
);
5960 UFWORDX("=", STREQU
);
5961 UFWORDX("=CI", STREQUCI
);
5962 UFWORDX("CMP", STRCMP
);
5963 UFWORDX("CMP-CI", STRCMPCI
);
5964 UFWORDX("UNESCAPE", STR_UNESCAPE
);
5965 ufoSetForthOnlyDefs();
5967 // some useful words
5968 UFWORDX_IMM("(", COMMENTPAREN
);
5969 UFWORDX_IMM("\\", COMMENTEOL
);
5970 UFWORDX_IMM(";;", COMMENTEOL
);
5971 UFWORDX_IMM("(*", COMMENTML
);
5972 UFWORDX_IMM("((", COMMENTML_NESTED
);
5983 UFWORDX("LASTCR?", LASTCRQ
);
5984 UFWORDX("LASTCR!", LASTCRSET
);
5988 UFWORDX("U.", UDOT
);
5989 UFWORDX(".R", DOTR
);
5990 UFWORDX("U.R", UDOTR
);
5995 UFWORDX("-", MINUS
);
5997 UFWORDX("U*", UMUL
);
5999 UFWORDX("U/", UDIV
);
6000 UFWORDX("MOD", MOD
);
6001 UFWORDX("UMOD", UMOD
);
6002 UFWORDX("/MOD", DIVMOD
);
6003 UFWORDX("U/MOD", UDIVMOD
);
6007 UFWORDX(">", GREAT
);
6008 UFWORDX("<=", LESSEQU
);
6009 UFWORDX(">=", GREATEQU
);
6010 UFWORDX("U<", ULESS
);
6011 UFWORDX("U>", UGREAT
);
6012 UFWORDX("U<=", ULESSEQU
);
6013 UFWORDX("U>=", UGREATEQU
);
6016 UFWORDX("BOUNDS?", BOUNDSQ
);
6019 UFWORDX("<>", NOTEQU
);
6020 UFWORDX("!=", NOTEQU
);
6025 UFWORDX("LOGAND", LOGAND
);
6027 UFWORDX("LOGOR", LOGOR
);
6030 UFWORDX("1+", ONEPLUS
);
6031 UFWORDX("1-", ONEMINUS
);
6032 UFWORDX("2+", TWOPLUS
);
6033 UFWORDX("2-", TWOMINUS
);
6034 UFWORDX("3+", THREEPLUS
);
6035 UFWORDX("3-", THREEMINUS
);
6036 UFWORDX("4+", FOURPLUS
);
6037 UFWORDX("4-", FOURMINUS
);
6038 UFWORDX("2U*", ONESHL
);
6039 UFWORDX("2U/", ONESHR
);
6044 UFWORDX_IMM("\"", STRQ
);
6045 UFWORDX_IMM(".\"", STRDOTQ
);
6047 UFWORDX("LITERAL", LITERAL
);
6048 UFWORDX_IMM("COMPILE", COMPILE_IMM
);
6049 UFWORDX_IMM("[COMPILE]", XCOMPILE_IMM
);
6050 UFWORDX_IMM("[']", XTICK_IMM
);
6051 UFWORDX_IMM("['PFA]", XTICKPFA_IMM
);
6053 UFWORDX_IMM("'", TICK_IMM
);
6054 UFWORDX_IMM("'PFA", TICKPFA_IMM
);
6056 UFWORDX_IMM("EXIT", EXIT_IMM
);
6062 UFWORDX_IMM("THEN", ENDIF
);
6066 UFWORDX_IMM("NOT-WHILE", NOT_WHILE
);
6067 UFWORDX_IMM("REPEAT", AGAIN
);
6069 UFWORDX_IMM("NOT-UNTIL", NOT_UNTIL
);
6071 UFWORD_IMM(ENDCASE
);
6073 UFWORDX_IMM("&OF", AND_OF
);
6075 UFWORD_IMM(OTHERWISE
);
6078 UFWORDX_IMM("+LOOP", PLOOP
);
6081 UFWORDX("I'", ITICK
);
6082 UFWORDX("J'", JTICK
);
6084 UFWORDX(":", COLON
);
6085 UFWORDX_IMM(";", SEMI
);
6087 UFWORDX("CREATE;", CREATE_SEMI
);
6088 UFWORDX("DOES>", DOES
);
6091 UFWORDX_IMM("VOCID:", VOCID_IMM
);
6095 UFWORD(DEFINITIONS
);
6096 UFWORDX("NESTED-VOCABULARY", NESTED_VOCABULARY
);
6097 UFWORDX("<PUBLIC-WORDS>", VOC_PUBLIC_MODE
);
6098 UFWORDX("<HIDDEN-WORDS>", VOC_HIDDEN_MODE
);
6099 UFWORDX("<PROTECTED-WORDS>", VOC_PROTECTED_MODE
);
6100 UFWORDX("<UNPROTECTED-WORDS>", VOC_UNPROTECTED_MODE
);
6102 UFWORDX("(PROTECTED)", PAR_PROTECTED
);
6103 UFWORDX("(HIDDEN)", PAR_HIDDEN
);
6105 UFWORDX_IMM("LOCALS:", LOCALS_IMM
);
6106 UFWORDX_IMM("ARGS:", ARGS_IMM
);
6109 UFWORDX("(PARSE)", PAR_PARSE
);
6110 UFWORDX("(WORD-OR-PARSE)", PAR_WORD_OR_PARSE
);
6112 UFWORDX("PARSE-TO-HERE", PARSE_TO_HERE
);
6113 UFWORDX("PARSE-NAME", PARSE_NAME
);
6114 UFWORDX("PARSE", PARSE
);
6116 UFWORDX("TIB-ADVANCE-LINE", TIB_ADVANCE_LINE
);
6117 UFWORDX("TIB-CHAR?", TIB_PEEKCH
);
6118 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
6119 UFWORDX("TIB-GETCH", TIB_GETCH
);
6120 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
6122 UFWORDX(">IN", GET_IN_ADDR
);
6123 UFWORDX("TIB", GET_TIB_ADDR
);
6124 UFWORDX("TIB-SIZE", GET_TIB_SIZE
);
6128 UFWORDX("(NUMBER)", XNUMBER
);
6131 UFWORDX("VALUE", VALUE
);
6132 UFWORDX("VAR-NOALLOT", VAR_NOALLOT
);
6133 UFWORDX("VARIABLE", VARIABLE
);
6134 UFWORDX("CONSTANT", CONSTANT
);
6135 UFWORDX("DEFER", DEFER
);
6136 UFWORDX("LOAD-DATA-FILE", LOAD_DATA_FILE
);
6137 UFWORDX("N-ALLOT", N_ALLOT
);
6138 UFWORDX("ALLOT", ALLOT
);
6139 UFWORDX("HERE", HERE
);
6140 UFWORDX("PAD", PAD
);
6141 UFWORDX_IMM("TO", TO_IMM
);
6142 UFWORDX("NAMED-TO", NAMED_TO
);
6143 UFWORDX("CFA->PFA", CFA2PFA
);
6144 UFWORDX("LATEST-CFA", LATEST_CFA
);
6146 UFWORDX_IMM("[", LSQBRACKET_IMM
);
6147 UFWORDX("]", RSQBRACKET
);
6149 UFWORDX_IMM("[:", CODEBLOCK_START_IMM
);
6150 UFWORDX_IMM(";]", CODEBLOCK_END_IMM
);
6151 /* code blocks are used like this:
6152 : A [: ( addr count -- res ) TYPE 0 ;] ASM-FOREACH-LABEL DROP ;
6153 i.e. it creates inlined code block, and returns its CFA.
6158 (void)ufoCreateVocSetOnlyDefs("URASM", NULL
);
6159 // UrAsm label types
6160 // WARNING! keep in sync with C source!
6161 ufoDefineConstant("LBL-TYPE-UNKNOWN", UFO_ZX_LABEL_UNKNOWN
);
6162 ufoDefineConstant("LBL-TYPE-VAR", UFO_ZX_LABEL_VAR
);
6163 ufoDefineConstant("LBL-TYPE-EQU", UFO_ZX_LABEL_EQU
);
6164 ufoDefineConstant("LBL-TYPE-CODE", UFO_ZX_LABEL_CODE
);
6165 ufoDefineConstant("LBL-TYPE-STOFS", UFO_ZX_LABEL_STOFS
);
6166 ufoDefineConstant("LBL-TYPE-DATA", UFO_ZX_LABEL_DATA
);
6168 UFWORDX("C,", ZX_CCOMMA
);
6169 UFWORDX("W,", ZX_WCOMMA
);
6170 UFWORDX("C@", ZX_CPEEK
);
6171 UFWORDX("C!", ZX_CPOKE
);
6172 UFWORDX("W@", ZX_WPEEK
);
6173 UFWORDX("W!", ZX_WPOKE
);
6175 UFWORDX("RESERVED?", ZX_RESERVEDQ
);
6176 UFWORDX("RESERVED!", ZX_RESERVEDS
);
6178 UFWORDX("HAS-LABEL?", UR_HAS_LABELQ
);
6179 UFWORDX("LABEL-TYPE?", UR_GET_LABELQ_TYPE
);
6180 UFWORDX("GET-LABEL", UR_GET_LABELQ
);
6181 UFWORDX("FOREACH-LABEL", UR_FOREACH_LABEL
);
6182 UFWORDX("SET-LABEL-VAR", UR_SET_LABEL_VAR
);
6183 UFWORDX("SET-LABEL-EQU", UR_SET_LABEL_EQU
);
6184 UFWORDX("SET-LABEL-CODE", UR_SET_LABEL_CODE
);
6185 UFWORDX("SET-LABEL-STOFS", UR_SET_LABEL_STOFS
);
6186 UFWORDX("SET-LABEL-DATA", UR_SET_LABEL_DATA
);
6187 UFWORDX("PASS@", UR_PASSQ
);
6189 UFWORDX("LOAD-DATA-FILE", ZX_LOAD_DATA_FILE
);
6191 UFWORDX("ORG@", UR_GETORG
);
6192 UFWORDX("DISP@", UR_GETDISP
);
6193 UFWORDX("ENT@", UR_GETENT
);
6194 UFWORDX("ORG!", UR_SETORG
);
6195 UFWORDX("DISP!", UR_SETDISP
);
6196 UFWORDX("ENT!", UR_SETENT
);
6198 UFWORDX("WARNING", ASM_WARNING
);
6199 UFWORDX("ERROR", ASM_ERROR
);
6200 ufoSetForthOnlyDefs();
6203 // conditional compilation
6204 UFWORDX_IMM("$IF", DLR_IF_IMM
);
6205 UFWORDX_IMM("$ELSE", DLR_ELSE_IMM
);
6206 UFWORDX_IMM("$ELIF", DLR_ELIF_IMM
);
6207 UFWORDX_IMM("$ENDIF", DLR_ENDIF_IMM
);
6209 UFWORDX_IMM("$DEFINE", DLR_DEFINE
);
6210 UFWORDX_IMM("$UNDEF", DLR_UNDEF
);
6212 UFWORDX_IMM("$LABEL-DATA:", DLR_LABEL_DATA_IMM
);
6213 UFWORDX_IMM("$LABEL-CODE:", DLR_LABEL_CODE_IMM
);
6215 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE
);
6216 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE
);
6218 UFWORDX("INCLUDE", INCLUDE
);
6221 UFWORDX("?ERROR", QERROR
);
6222 (void)ufoCreateVocSetOnlyDefs("UFO", NULL
);
6223 UFWORDX("FATAL", UFO_FATAL
);
6225 // UrForth internal word types
6226 ufoDefineConstant("WORD-TYPE-NONE", 0);
6227 ufoDefineConstant("WORD-TYPE-CODE", 1);
6228 ufoDefineConstant("WORD-TYPE-FORTH", 2);
6229 ufoDefineConstant("WORD-TYPE-VARIABLE", 3);
6230 ufoDefineConstant("WORD-TYPE-VALUE", 4);
6231 ufoDefineConstant("WORD-TYPE-CONSTANT", 5);
6232 ufoDefineConstant("WORD-TYPE-DEFER", 6);
6233 ufoDefineConstant("WORD-TYPE-DOES", 7);
6234 ufoDefineConstant("WORD-TYPE-VOCABULARY", 8);
6236 UFWORDX("VOC-LATEST", WORDS_ITER_NEW
);
6237 UFWORDX("WORD-PREV", WORDS_ITER_PREV
);
6238 UFWORDX("WORD-NAME", WORDS_ITER_NAME
);
6239 UFWORDX("WORD-PFA", WORDS_ITER_PFA
);
6240 UFWORDX("WORD-IMM?", WORDS_ITER_IMMQ
);
6241 UFWORDX("WORD-PROT?", WORDS_ITER_PROTQ
);
6242 UFWORDX("WORD-HIDDEN?", WORDS_ITER_HIDDENQ
);
6243 UFWORDX("WORD-TYPE?", WORDS_ITER_TYPEQ
);
6244 UFWORDX("FOREACH-WORD", UFO_FOREACH_WORD
);
6245 UFWORDX("FOREACH-VOC", UFO_FOREACH_VOC
);
6247 UFWORDX("<MODE@>", UFO_MODER
);
6249 ufoSetForthOnlyDefs();
6252 (void)ufoCreateVocSetOnlyDefs("DEBUG", NULL
);
6253 UFWORDX("DUMP-STACK", DUMP_STACK
);
6254 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
6255 UFWORDX("DECOMPILE", UFO_DECOMPILE_INTERNAL
);
6256 UFWORDX("BP", UFO_BP
);
6257 UFWORDX("BUCKET-STATS", PAR_UFO_BUCKET_STATS
);
6258 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
6259 ufoSetForthOnlyDefs();
6265 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6268 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
6270 UFWORDX_IMM("$END_FORTH", DLR_END_FORTH
);
6271 UFWORDX_IMM("$END-FORTH", DLR_END_FORTH
);
6272 //UFWORDX("$END-FORTH", DLR_END_FORTH_NOIMM);
6275 UFWORDX("ZXADDR?", ZXADDRQ
);
6276 UFWORDX("(TOZX)", TOZX
);
6277 UFWORDX_IMM("TOZX", TOZX_IMM
);
6278 UFWORDX("(FROMZX)", FROMZX
);
6279 UFWORDX_IMM("FROMZX", FROMZX_IMM
);
6283 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6287 //==========================================================================
6291 // address interpreter
6293 //==========================================================================
6294 static void ufoRunVM (void) {
6296 while (!ufoStopVM
) {
6297 uint32_t cfaidx
= ufoImgGetU32(ufoIP
++);
6298 if (cfaidx
& UFO_RS_CFA_BIT
) {
6299 cfaidx
&= UFO_RS_CFA_MASK
;
6300 if (cfaidx
>= ufoCFAsUsed
) {
6301 ufoFatal("UFO tried to execute an unknown word: 0x%08x (max is 0x%08x); IP=0x%08x", cfaidx
, ufoCFAsUsed
, ufoIP
-1);
6303 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
6304 if (fw
== NULL
) ufoFatal("VM internal error: empty CFA");
6307 ufoFatal("VM tried to execute something that is not a word");
6314 //==========================================================================
6318 //==========================================================================
6319 static void ufoRunIt (const char *wname
) {
6320 UForthWord
*fw
= ufoAlwaysWord(wname
);
6321 if (fw
->cfa
!= &ufoDoForth
) {
6322 ufoFatal("UFO '%s' word is not a Forth word", wname
);
6324 ufoExecuteNativeWordInVM(fw
);
6328 //==========================================================================
6332 //==========================================================================
6333 void ufoInlineInit (void) {
6334 ufoMode
= UFO_MODE_NATIVE
;
6335 ufoTrueValue
= ~0u; // -1 is better!
6337 ufoInFileLine
= 0; ufoCondStLine
= -1;
6338 ufoInFileName
= NULL
;
6340 ufoLastIncPath
= NULL
;
6344 ufoSetStateInterpret();
6351 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
6352 FILE *ufl
= ufoOpenFileOrDir(&ufmname
);
6355 ufoInFileName
= ufmname
;
6357 setLastIncPath(ufoInFileName
);
6364 //==========================================================================
6368 //==========================================================================
6369 void ufoInlineRun (void) {
6370 if (ufoMode
== UFO_MODE_NONE
) {
6373 ufoMode
= UFO_MODE_NATIVE
;
6375 if (setjmp(ufoInlineQuitJP
) == 0) {
6377 //UFCALL(INTERPRET);
6378 ufoRunIt("UFO-RUN-LOOP");
6379 ufo_assert(0); // the thing that should not be
6381 while (ufoFileStackPos
!= 0) ufoPopInFile();
6386 //==========================================================================
6390 //==========================================================================
6391 uint32_t ufoIsMacro (const char *wname
) {
6392 if (ufoMode
!= UFO_MODE_NONE
) {
6393 UForthWord
*fw
= ufoFindWordMacro(wname
);
6394 if (fw
!= NULL
&& fw
->cfa
== &ufoDoForth
) return fw
->cfaidx
;
6400 //==========================================================================
6404 //==========================================================================
6405 void ufoMacroRun (uint32_t cfaidx
, const char *line
, const char *fname
, int lnum
) {
6406 ufo_assert(ufoMode
!= UFO_MODE_NONE
);
6407 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfaidx
);
6408 ufoMode
= UFO_MODE_MACRO
;
6409 if (fw
->cfa
!= &ufoDoForth
) {
6410 ufoFatal("UFO '%s' macro word is not a Forth word", fw
->name
);
6413 if (setjmp(ufoInlineQuitJP
) == 0) {
6415 ufoLoadMacroLine(line
, fname
, lnum
);
6416 ufoExecuteNativeWordInVM(fw
);
6417 while (ufoFileStackPos
!= 0) ufoPopInFile();
6419 while (ufoFileStackPos
!= 0) ufoPopInFile();
6420 ufoFatal("wtf with UFO macro?!");