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 UFO_FORCE_INLINE
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 static int strEquCI (const char *s0
, const char *s1
) {
89 while (res
&& *s0
&& *s1
) {
90 char c0
= *s0
++; if (c0
>= 'A' && c0
<= 'Z') c0
= c0
- 'A' + 'a';
91 char c1
= *s1
++; if (c1
>= 'A' && c1
<= 'Z') c1
= c1
- 'A' + 'a';
94 return (res
&& s0
[0] == 0 && s1
[0] == 0);
98 //==========================================================================
102 //==========================================================================
103 UFO_FORCE_INLINE
char toUpper (char ch
) {
104 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
108 //==========================================================================
112 //==========================================================================
113 static int digitInBase (char ch
, int base
) {
114 if (ch
< '0') return -1;
116 if (ch
>= '0'+base
) return -1;
120 if (ch
<= '9') return ch
-'0';
121 if (ch
< 'A' || ch
> 'A'+base
-10) return -1;
123 return (ch
< base
? ch
: -1);
127 // ////////////////////////////////////////////////////////////////////////// //
128 #define UFW_FLAG_IMMEDIATE (1u<<0)
129 #define UFW_FLAG_PROTECTED (1u<<1)
130 #define UFW_FLAG_HIDDEN (1u<<2)
131 #define UFW_FLAG_VOC_HIDDEN (1u<<3)
133 #define UFW_IS_IMM(fw_) (((fw_)->flags&UFW_FLAG_IMMEDIATE) != 0)
134 #define UFW_IS_PROT(fw_) (((fw_)->flags&UFW_FLAG_PROTECTED) != 0)
135 #define UFW_IS_HID(fw_) (((fw_)->flags&UFW_FLAG_HIDDEN) != 0)
136 #define UFW_IS_VOC_HID(fw_) (((fw_)->flags&UFW_FLAG_VOC_HIDDEN) != 0)
139 typedef struct UForthWord_t UForthWord
;
140 struct UForthWord_t
{
142 UForthWord
*prevAll
; // in global list
143 UForthWord
*prevVoc
; // in vocabulary
144 void (*cfa
) (UForthWord
*self
); // `self` may be NULL if called from the internal code
145 uint32_t cfaidx
; // in `ufoForthCFAs`
146 uint32_t pfastart
; // pointer to image
147 uint32_t pfaend
; // set in `;`
148 uint32_t pfa
; // pointer to image
149 uint32_t flags
; // see `UFW_FLAG_xxx`
150 // parent vocabulary link (for vocabularies only)
152 UForthWord
**buckets
; // vocabulary hash table
153 // hash and bucket link
158 #define UFO_DICT_HASH_BUCKETS (1024u)
159 static UForthWord
*ufoForthDict
= NULL
;
160 static UForthWord
*ufoColonWord
= NULL
;
162 static jmp_buf ufoInlineQuitJP
;
164 #define UFO_MAX_WORDS (65536u)
165 static UForthWord
**ufoForthCFAs
= NULL
;
166 static unsigned ufoCFAsUsed
= 0;
168 #define UFO_ZX_ADDR_BIT (1u<<30)
169 #define UFO_ZX_ADDR_MASK (0xffffU)
171 #define UFO_RS_CFA_BIT (1u<<31)
172 #define UFO_RS_CFA_MASK ((1u<<31)-1u)
174 #define UFO_ENSURE_NATIVE_ADDR(adr_) do { \
175 const uint32_t aa = (uint32_t)(adr_); \
176 if (aa & UFO_ZX_ADDR_BIT) ufoFatal("unexpected ZX address"); \
177 if (aa & UFO_RS_CFA_BIT) ufoFatal("unexpected CFA address"); \
180 #define UFO_ENSURE_NATIVE_CFA(adr_) ({ \
181 const uint32_t aa = (uint32_t)(adr_); \
182 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
183 if ((aa&UFO_RS_CFA_MASK) >= ufoCFAsUsed || ufoForthCFAs[(aa&UFO_RS_CFA_MASK)] == NULL) ufoFatal("invalid CFA address"); \
187 #define UFO_GET_NATIVE_CFA(adr_) ({ \
188 uint32_t aa = (uint32_t)(adr_); \
189 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
190 aa &= UFO_RS_CFA_MASK; \
191 if (aa >= ufoCFAsUsed || ufoForthCFAs[aa] == NULL) ufoFatal("invalid CFA address"); \
195 #define FW_GET_CFAIDX(fw_) ((fw_)->cfaidx & UFO_RS_CFA_MASK)
196 #define FW_SET_CFAIDX(fw_,ci_) ((fw_)->cfaidx = (((ci_) & UFO_RS_CFA_MASK) | UFO_RS_CFA_BIT))
198 static uint32_t *ufoImage
= NULL
;
199 static uint32_t ufoImageSize
= 0;
200 static uint32_t ufoImageUsed
= 0;
202 static uint32_t ufoIP
= 0; // in image
203 static uint32_t ufoSP
= 0; // points AFTER the last value pushed
204 static uint32_t ufoRP
= 0; // points AFTER the last value pushed
205 static uint32_t ufoRPTop
= 0; // stop when RP is this, and we're doing EXIT
207 static uint32_t ufoTrueValue
= ~0u;
209 // the compiler works in two modes
210 // first mode is "native"
211 // only forth variables are allowed, and they're leaving ZX addresses
212 // second mode is "zx"
213 // in this mode, various creation words will create things in ZX memory.
214 // note that in interpret mode it is still possible to perform various
215 // native calculations, and call native words.
216 // but calling native word while compiling ZX code is possible only if it
217 // is an immediate one.
220 UFO_MODE_NATIVE
= 0, // executing forth code
221 UFO_MODE_MACRO
= 1, // executing forth asm macro
223 static uint32_t ufoMode
= UFO_MODE_NONE
;
225 // hack for `IMMEDIATE`
227 // only one of those can be set! (invariant)
228 static UForthWord
*ufoLastDefinedNativeWord
= NULL
;
230 #define UFO_DSTACK_SIZE (8192)
231 #define UFO_RSTACK_SIZE (8192)
232 static uint32_t *ufoDStack
= NULL
;
233 static uint32_t *ufoRStack
= NULL
;
236 typedef struct UForthLocRecord_t
{
237 char name
[128]; // local name
238 uint32_t lidx
; // offset from the current local ptr
239 struct UForthLocRecord_t
*next
;
242 #define UFO_LSTACK_SIZE (8192)
243 static uint32_t *ufoLStack
= NULL
;
244 static uint32_t ufoLP
, ufoLBP
; // bottom, base; nice names, yeah
245 // used in the compiler
246 static UForthLocRecord
*ufoLocals
= NULL
;
248 // dynamically allocated text input buffer
249 // always ends with zero (this is word name too)
250 // first 512 cells of image is TIB
251 static uint32_t ufoTIBAreaSize
= 512;
253 static uint32_t ufoAddrTIB
= 0; // TIB; 0 means "in TIB area", otherwise in the dictionary
254 static uint32_t ufoAddrIN
= 0; // >IN
256 static uint32_t ufoAddrContext
= 0; // CONTEXT
257 static uint32_t ufoAddrCurrent
= 0; // CURRENT
258 static uint32_t ufoDefaultVocFlags
= 0;
259 static uint32_t ufoLastVoc
= 0;
261 static uint32_t ufoBASEaddr
; // address of "BASE" variable
262 static uint32_t ufoSTATEaddr
; // address of "STATE" variable
263 static uint32_t ufoStopVM
;
264 static int ufoInColon
; // should be signed
266 #define UFO_PAD_OFFSET (2048u)
267 #define UFO_PAD1_OFFSET (4096u)
269 #define UFO_MAX_NESTED_INCLUDES (32)
276 uint32_t savedTIBSize
;
279 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
280 static uint32_t ufoFileStackPos
; // after the last used item
282 static FILE *ufoInFile
= NULL
;
283 static char *ufoInFileName
= NULL
;
284 static char *ufoLastIncPath
= NULL
;
285 static int ufoInFileLine
= 0;
286 static int ufoCondStLine
= -1;
288 static int ufoLastEmitWasCR
= 1;
289 static uint32_t ufoCSP
= 0;
290 static int ufoInCondIf
= 0;
292 #define UFO_VOCSTACK_SIZE (16u)
293 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
294 static uint32_t ufoVSP
;
295 static uint32_t ufoForthVocCFA
;
296 static uint32_t ufoCompSuppVocCFA
;
297 static uint32_t ufoMacroVocCFA
;
299 static char ufoCurrFileLine
[520];
300 // used to extract strings from the image
301 static char ufoTempCharBuf
[1024];
304 // ////////////////////////////////////////////////////////////////////////// //
306 static void ufoDbgDeinit (void);
308 static void ufoClearCondDefines (void);
309 static void ufoRunVM (void);
311 static int ufoParseConditionExpr (int doskip
);
314 //==========================================================================
318 //==========================================================================
319 static void setLastIncPath (const char *fname
) {
320 if (fname
== NULL
|| fname
[0] == 0) {
321 if (ufoLastIncPath
) free(ufoLastIncPath
);
322 ufoLastIncPath
= strdup(".");
324 if (ufoLastIncPath
) free(ufoLastIncPath
);
325 ufoLastIncPath
= strdup(fname
);
326 char *lslash
= ufoLastIncPath
;
327 char *cpos
= ufoLastIncPath
;
330 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
332 if (*cpos
== '/') lslash
= cpos
;
341 // ////////////////////////////////////////////////////////////////////////// //
342 UFO_FORCE_INLINE
uint32_t ufoPadAddr (void) {
343 return (ufoImageUsed
+ UFO_PAD_OFFSET
+ 1023u) / 1024u * 1024u;
347 static void ufoDoForth (UForthWord
*self
);
348 static void ufoDoVariable (UForthWord
*self
);
349 static void ufoDoValue (UForthWord
*self
);
350 static void ufoDoConst (UForthWord
*self
);
351 static void ufoDoDefer (UForthWord
*self
);
352 static void ufoDoVoc (UForthWord
*self
);
355 //==========================================================================
359 //==========================================================================
360 static void ufoErrorWriteFile (FILE *fo
) {
362 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
364 fprintf(fo
, "UFO ERROR somewhere in time: ");
369 //==========================================================================
373 //==========================================================================
374 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
375 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
377 ufoErrorWriteFile(stderr
);
378 vfprintf(stderr
, fmt
, ap
);
385 //==========================================================================
389 //==========================================================================
390 static void ufoStackTrace (void) {
391 // dump data stack (top 16)
392 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
393 uint32_t xsp
= ufoSP
;
394 if (xsp
> 16) xsp
= 16;
395 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
396 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
397 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
399 //if (ufoSP != 0) fputc('\n', stderr);
401 // dump return stack (top 32)
402 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
404 uint32_t rscount
= 0;
405 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
406 while (rscount
!= 32 && rp
!= 0) {
408 uint32_t cfa
= ufoRStack
[rp
];
409 if (cfa
& UFO_RS_CFA_BIT
) {
410 cfa
&= UFO_RS_CFA_MASK
;
411 if (cfa
< ufoCFAsUsed
&& ufoForthCFAs
[cfa
] != NULL
) {
412 UForthWord
*fw
= ufoForthCFAs
[cfa
];
413 fprintf(stderr
, " %2u: %s\n", rscount
, fw
->name
);
415 fprintf(stderr
, " %2u: wutafuck?\n", rscount
);
425 //==========================================================================
429 //==========================================================================
430 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
431 void ufoFatal (const char *fmt
, ...) {
434 ufoErrorMsgV(fmt
, ap
);
436 #ifdef UFO_DEBUG_FATAL_ABORT
443 //==========================================================================
447 //==========================================================================
448 static void ufoWipeLocRecords (void) {
449 while (ufoLocals
!= NULL
) {
450 UForthLocRecord
*r
= ufoLocals
;
451 ufoLocals
= ufoLocals
->next
;
457 //==========================================================================
461 // return !0 for duplicate
463 //==========================================================================
464 static void ufoNewLocal (const char *name
) {
467 if (name
== NULL
|| name
[0] == 0) ufoFatal("empty local name");
468 const size_t nlen
= strlen(name
);
469 if (nlen
> 127) ufoFatal("local name too long");
470 for (size_t f
= 0; f
< nlen
; f
+= 1) {
472 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
473 //if (ch == ':' || ch == '!') ufoFatal("invalid local name '%s'", name);
478 UForthLocRecord
*r
= ufoLocals
;
479 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
481 if (r
!= NULL
) ufoFatal("duplocate local '%s'", name
);
483 r
= calloc(1, sizeof(*r
));
484 strcpy(r
->name
, buf
);
485 if (ufoLocals
== 0) r
->lidx
= 1; else r
->lidx
= ufoLocals
->lidx
+ 1;
486 r
->next
= ufoLocals
; ufoLocals
= r
;
490 //==========================================================================
494 //==========================================================================
495 static UForthLocRecord
*ufoFindLocal (const char *name
, int *wantStore
) {
498 if (wantStore
) *wantStore
= 0;
499 if (name
== NULL
|| name
[0] != ':' || name
[1] == 0) return NULL
;
500 name
+= 1; // skip colon
501 size_t nlen
= strlen(name
);
502 if (nlen
!= 0 && name
[nlen
- 1] == '!') {
503 if (wantStore
) *wantStore
= 1;
505 if (nlen
== 0) return NULL
;
507 if (nlen
> 127) return NULL
;
508 for (size_t f
= 0; f
< nlen
; f
+= 1) {
510 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
515 UForthLocRecord
*r
= ufoLocals
;
516 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
522 // ////////////////////////////////////////////////////////////////////////// //
523 // working with the image
525 //==========================================================================
529 //==========================================================================
530 static void ufoImgEnsureSize (uint32_t addr
) {
531 UFO_ENSURE_NATIVE_ADDR(addr
);
532 if (addr
>= ufoImageSize
) {
533 // 256MB should be enough for everyone!
534 // one cell is 4 bytes, so max address is 64MB
535 if (addr
>= 0x04000000U
) {
536 ufoFatal("UFO image grown too big (addr=0%08XH)", addr
);
538 const uint32_t osz
= ufoImageSize
;
539 // grow by 4MB steps (16 real MBs)
540 uint32_t nsz
= (addr
|0x003fffffU
) + 1U;
541 uint32_t *nimg
= realloc(ufoImage
, nsz
* sizeof(ufoImage
[0]));
543 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
544 ufoImageSize
/ 1024u / 1024u,
545 nsz
/ 1024u / 1024u);
549 memset(ufoImage
+ osz
, 0, (nsz
- osz
) * sizeof(ufoImage
[0]));
554 //==========================================================================
558 //==========================================================================
559 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, uint32_t value
) {
560 UFO_ENSURE_NATIVE_ADDR(addr
);
561 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
562 ufoImage
[addr
] = value
&0xffU
;
566 //==========================================================================
570 //==========================================================================
571 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, uint32_t value
) {
572 UFO_ENSURE_NATIVE_ADDR(addr
);
573 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
574 ufoImage
[addr
] = value
;
578 //==========================================================================
582 //==========================================================================
583 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
584 ufoImgPutU8(ufoImageUsed
, value
);
589 //==========================================================================
593 //==========================================================================
594 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
595 ufoImgPutU32(ufoImageUsed
, value
);
600 //==========================================================================
604 //==========================================================================
605 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
606 UFO_ENSURE_NATIVE_ADDR(addr
);
607 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
608 return ufoImage
[addr
]&0xffU
;
612 //==========================================================================
616 //==========================================================================
617 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
618 UFO_ENSURE_NATIVE_ADDR(addr
);
619 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
620 return ufoImage
[addr
];
624 //==========================================================================
628 // 32 for native address
630 //==========================================================================
631 UFO_FORCE_INLINE
uint32_t ufoImgGetCounter (uint32_t addr
) {
632 UFO_ENSURE_NATIVE_ADDR(addr
);
633 return ufoImgGetU32(addr
);
637 //==========================================================================
641 //==========================================================================
642 static FILE *ufoOpenFileOrDir (char **fnameptr
) {
647 if (fnameptr
== NULL
) return NULL
;
650 fprintf(stderr
, "***:fname=<%s>\n", fname
);
653 if (fname
== NULL
|| fname
[0] == 0 || stat(fname
, &st
) != 0) return NULL
;
655 if (S_ISDIR(st
.st_mode
)) {
656 tmp
= calloc(1, strlen(fname
) + 128);
657 ufo_assert(tmp
!= NULL
);
658 sprintf(tmp
, "%s/%s", fname
, "zzmain.f");
659 free(fname
); fname
= tmp
; *fnameptr
= tmp
;
661 fprintf(stderr
, "***: <%s>\n", fname
);
665 return fopen(fname
, "rb");
669 //==========================================================================
673 //==========================================================================
674 static void ufoPushInFile (void) {
675 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
676 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
678 stk
->fname
= ufoInFileName
;
679 stk
->fline
= ufoInFileLine
;
680 stk
->incpath
= ufoLastIncPath
;
681 // save TIB (if it is the default)
682 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
683 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
684 stk
->savedTIBSize
= 0;
685 stk
->savedTIB
= NULL
;
686 if (tib
== 0 && in
< ufoTIBAreaSize
) {
687 while (ufoImgGetU8(tib
+ in
+ stk
->savedTIBSize
) != 0) stk
->savedTIBSize
+= 1;
688 if (stk
->savedTIBSize
!= 0) {
689 stk
->savedTIB
= malloc(stk
->savedTIBSize
);
690 if (stk
->savedTIB
== NULL
) ufoFatal("out of memory for include stack");
691 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
692 stk
->savedTIB
[f
] = ufoImgGetU8(tib
+ in
+ f
);
696 ufoFileStackPos
+= 1;
698 ufoInFileName
= NULL
;
700 ufoLastIncPath
= NULL
;
704 //==========================================================================
708 //==========================================================================
709 static void ufoPopInFile (void) {
710 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
711 if (ufoInFileName
) free(ufoInFileName
);
712 if (ufoInFile
) fclose(ufoInFile
);
713 if (ufoLastIncPath
) free(ufoLastIncPath
);
714 ufoFileStackPos
-= 1;
715 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
717 ufoInFileName
= stk
->fname
;
718 ufoInFileLine
= stk
->fline
;
719 ufoLastIncPath
= stk
->incpath
;
721 // also, restore current line, because some code may need it
722 if (stk
->savedTIBSize
>= ufoTIBAreaSize
) ufoFatal("restored TIB too big");
723 if (stk
->savedTIBSize
>= sizeof(ufoCurrFileLine
)) {
724 ufoFatal("post-include restored source line is too long");
726 ufoImgPutU32(ufoAddrTIB
, 0);
727 ufoImgPutU32(ufoAddrIN
, 0);
728 if (stk
->savedTIBSize
!= 0) {
729 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
730 ufoImgPutU8(f
, stk
->savedTIB
[f
]);
731 ufoCurrFileLine
[f
] = (char)(stk
->savedTIB
[f
]&0xff);
735 ufoImgPutU8(stk
->savedTIBSize
, 0);
736 ufoCurrFileLine
[stk
->savedTIBSize
] = 0;
737 #ifdef UFO_DEBUG_INLCUDE
738 fprintf(stderr
, "INC-POP: <%s>\n", ufoCurrFileLine
);
743 //==========================================================================
747 //==========================================================================
748 void ufoDeinit (void) {
752 if (ufoInFileName
) free(ufoInFileName
);
753 if (ufoLastIncPath
) free(ufoLastIncPath
);
754 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
;
757 while (ufoForthDict
!= NULL
) {
758 UForthWord
*fw
= ufoForthDict
;
759 if (fw
->buckets
!= NULL
) free(fw
->buckets
);
760 ufoForthDict
= fw
->prevAll
;
776 ufoSP
= 0; ufoRP
= 0; ufoRPTop
= 0;
777 ufoLP
= 0; ufoLBP
= 0;
778 ufoMode
= UFO_MODE_NATIVE
;
779 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
788 ufoAddrTIB
= 0; ufoAddrIN
= 0;
790 ufoLastDefinedNativeWord
= NULL
;
792 ufoLastEmitWasCR
= 1;
797 ufoClearCondDefines();
805 // ////////////////////////////////////////////////////////////////////////// //
808 UFO_FORCE_INLINE
uint32_t ufoGetTIB (void) {
809 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrTIB
);
810 return ufoImage
[ufoAddrTIB
];
813 UFO_FORCE_INLINE
void ufoSetTIB (uint32_t value
) {
814 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrTIB
);
815 ufoImage
[ufoAddrTIB
] = value
;
818 UFO_FORCE_INLINE
uint32_t ufoGetIN (void) {
819 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrIN
);
820 return ufoImage
[ufoAddrIN
];
823 UFO_FORCE_INLINE
void ufoSetIN (uint32_t value
) {
824 if (ufoAddrTIB
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", ufoAddrIN
);
825 ufoImage
[ufoAddrIN
] = value
;
830 // ////////////////////////////////////////////////////////////////////////// //
831 // 1: compiling; 0: interpreting
832 UFO_FORCE_INLINE
int ufoGetState (void) { return (int)ufoImgGetU32(ufoSTATEaddr
); }
833 // 1: compiling; 0: interpreting
834 UFO_FORCE_INLINE
void ufoSetState (int v
) { ufoImgPutU32(ufoSTATEaddr
, (uint32_t)v
); }
836 UFO_FORCE_INLINE
void ufoSetStateCompile (void) { ufoSetState(1); }
837 UFO_FORCE_INLINE
void ufoSetStateInterpret (void) { ufoSetState(0); }
839 UFO_FORCE_INLINE
int ufoIsCompiling () { return (ufoGetState() != 0); }
840 UFO_FORCE_INLINE
int ufoIsInterpreting () { return (ufoGetState() == 0); }
843 #define UFO_GET_CFAPROC(cfa_) ({ \
844 uint32_t xcfa = (cfa_); \
845 ((xcfa & UFO_RS_CFA_BIT) && (xcfa & UFO_RS_CFA_MASK) < ufoCFAsUsed ? \
846 ufoForthCFAs[(xcfa & UFO_RS_CFA_MASK)] : NULL); \
849 #define UFO_VALID_VOC_FW(fw_) ({ \
850 const UForthWord *xvfw = (fw_); \
851 (xvfw != NULL && xvfw->cfa == &ufoDoVoc); \
855 //==========================================================================
859 // will not link hidden words
861 //==========================================================================
862 static void ufoLinkWordToDict (UForthWord
*fw
) {
863 ufo_assert(fw
!= NULL
&& fw
->prevAll
== NULL
&& fw
->hash
== 0 && fw
->hlink
== NULL
);
864 if (fw
->name
== NULL
) fw
->name
= strdup("");
865 if (UFW_IS_HID(fw
)) {
869 // insert into hash bucket
870 fw
->hash
= joaatHashBufCI(fw
->name
, strlen(fw
->name
));
871 const uint32_t bucket
= fw
->hash
%UFO_DICT_HASH_BUCKETS
;
873 uint32_t cur
= ufoImgGetU32(ufoAddrCurrent
);
874 // we may have no vocabulary active
875 UForthWord
*voc
= UFO_GET_CFAPROC(cur
);
876 if (UFO_VALID_VOC_FW(voc
)) {
878 fprintf(stderr
, "REG: <%s> : hash=0%08XH; bucked=%u\n", fw
->name
, fw
->hash
, bucket
);
880 fw
->hlink
= voc
->buckets
[bucket
];
881 voc
->buckets
[bucket
] = fw
;
882 fw
->prevVoc
= voc
->latest
;
888 // append to linear list
889 fw
->prevAll
= ufoForthDict
;
894 //==========================================================================
898 //==========================================================================
899 static void ufoLinkVocab (UForthWord
*fw
, UForthWord
*parent
) {
900 if (UFO_VALID_VOC_FW(fw
)) {
901 ufo_assert(fw
->pfa
!= 0xffffffffU
&& FW_GET_CFAIDX(fw
) < ufoCFAsUsed
);
902 if (parent
!= fw
&& UFO_VALID_VOC_FW(parent
)) {
903 ufoImgPutU32(fw
->pfa
+ 1, parent
->cfaidx
);
905 ufoImgPutU32(fw
->pfa
+ 1, 0);
911 //==========================================================================
913 // ufoCreateVocabData
915 //==========================================================================
916 static void ufoCreateVocabData (UForthWord
*fw
) {
917 if (fw
!= NULL
&& fw
->cfa
== NULL
) {
918 ufo_assert(fw
->pfa
== 0xffffffffU
&& FW_GET_CFAIDX(fw
) < ufoCFAsUsed
&& fw
->buckets
== NULL
);
920 fw
->buckets
= calloc(1, sizeof(fw
->buckets
[0]) * UFO_DICT_HASH_BUCKETS
);
921 // pfa: cfa, parentvoc, prevvoc
922 fw
->pfa
= ufoImageUsed
;
923 fw
->pfastart
= ufoImageUsed
;
924 ufoImgEmitU32(fw
->cfaidx
); // our cfa
925 ufoImgEmitU32(0); // parent voc cfa
926 ufoImgEmitU32(ufoLastVoc
); // voc link
927 ufoLastVoc
= fw
->pfa
;
928 fw
->pfaend
= ufoImageUsed
;
929 ufoLastVoc
= fw
->cfaidx
;
934 //==========================================================================
938 //==========================================================================
939 static UForthWord
*ufoFindWordInVoc (const char *wname
, uint32_t hash
, UForthWord
*voc
,
942 UForthWord
*fw
= NULL
;
943 if (wname
&& wname
[0] != 0 && UFO_VALID_VOC_FW(voc
)) {
944 fw
= voc
->buckets
[hash
%UFO_DICT_HASH_BUCKETS
];
946 if (fw
->cfa
!= NULL
&& fw
->hash
== hash
&&
947 !UFW_IS_HID(fw
) && (allowvochid
|| !UFW_IS_VOC_HID(fw
)) &&
948 strEquCI(fw
->name
, wname
))
959 //==========================================================================
961 // ufoFindWordNameRes
963 //==========================================================================
964 static UForthWord
*ufoFindWordNameRes (const char *wname
) {
967 //FIXME: make this faster!
969 uint32_t lvcfa
= ufoLastVoc
;
970 UForthWord
*voc
= UFO_GET_CFAPROC(lvcfa
);
971 if (!UFO_VALID_VOC_FW(voc
) || wname
[0] == ':') return NULL
;
973 const char *colon
= strchr(wname
+ 1, ':');
974 if (colon
== NULL
|| colon
[1] == 0 || colon
[1] == ':') return NULL
;
975 size_t vnlen
= (size_t)(colon
- wname
);
976 if (vnlen
> 255) return NULL
;
978 // get initial vocabulary name
979 memcpy(tempwbuf
, wname
, vnlen
);
981 wname
= colon
+ 1; // skip colon
984 fprintf(stderr
, "NRES: INIT-VOC=<%s>; REST=<%s>\n", tempwbuf
, wname
);
987 uint32_t vhash
= joaatHashBufCI(tempwbuf
, vnlen
);
988 while (UFO_VALID_VOC_FW(voc
)) {
989 if (voc
->hash
== vhash
|| strEquCI(voc
->name
, tempwbuf
)) {
992 lvcfa
= ufoImgGetU32(voc
->pfa
+ 2);
993 voc
= UFO_GET_CFAPROC(lvcfa
);
997 fprintf(stderr
, " IVC: %p %d\n", voc
, UFO_VALID_VOC_FW(voc
));
1000 while (wname
!= NULL
&& UFO_VALID_VOC_FW(voc
)) {
1001 vhash
= joaatHashBufCI(wname
, strlen(wname
));
1002 fw
= ufoFindWordInVoc(wname
, vhash
, voc
, 1);
1003 if (fw
!= NULL
) return fw
;
1004 colon
= strchr(wname
, ':');
1005 if (colon
== NULL
) return NULL
;
1007 size_t vnlen
= (size_t)(colon
- wname
);
1008 if (vnlen
> 255) return NULL
;
1009 memcpy(tempwbuf
, wname
, vnlen
);
1010 tempwbuf
[vnlen
] = 0;
1011 wname
= colon
+ 1; // skip colon
1013 fprintf(stderr
, " XVOC=<%s>; XREST=<%s>\n", tempwbuf
, wname
);
1015 vhash
= joaatHashBufCI(tempwbuf
, vnlen
);
1016 voc
= ufoFindWordInVoc(tempwbuf
, vhash
, voc
, 1);
1023 //==========================================================================
1027 // ignore words with no CFA: those are not finished yet
1029 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
1031 //==========================================================================
1032 static UForthWord
*ufoFindWord (const char *wname
) {
1033 if (!wname
|| wname
[0] == 0) return NULL
;
1034 uint32_t cur
= ufoImgGetU32(ufoAddrContext
);
1035 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1039 // first search in current
1040 voc
= UFO_GET_CFAPROC(cur
);
1041 fw
= ufoFindWordInVoc(wname
, hash
, voc
, (cur
== ufoImgGetU32(ufoAddrContext
)));
1044 if (fw
== NULL
&& UFO_VALID_VOC_FW(voc
)) {
1045 uint32_t vocPPrev
= cur
;
1047 while (fw
== NULL
&& UFO_VALID_VOC_FW(voc
)) {
1048 uint32_t vocParent
= ufoImgGetU32(voc
->pfa
+ 1);
1049 if (vocParent
== vocPPrev
) break;
1050 // move prev pointer
1052 voc
= UFO_GET_CFAPROC(vocPPrev
);
1053 ufo_assert(UFO_VALID_VOC_FW(voc
));
1054 vocPPrev
= ufoImgGetU32(voc
->pfa
+ 1);
1058 voc
= UFO_GET_CFAPROC(vocParent
);
1059 fw
= ufoFindWordInVoc(wname
, hash
, voc
, (cur
== ufoImgGetU32(ufoAddrContext
)));
1063 // if not found, try name resolution
1064 if (fw
== NULL
) fw
= ufoFindWordNameRes(wname
);
1066 // now try vocabulary stack
1067 uint32_t vstp
= ufoVSP
;
1068 while (fw
== NULL
&& vstp
!= 0) {
1070 voc
= UFO_GET_CFAPROC(ufoVocStack
[vstp
]);
1071 fw
= ufoFindWordInVoc(wname
, hash
, voc
,
1072 (ufoVocStack
[vstp
] == ufoImgGetU32(ufoAddrContext
)));
1079 //==========================================================================
1083 //==========================================================================
1084 static UForthWord
*ufoFindWordMacro (const char *wname
) {
1085 if (!wname
|| wname
[0] == 0) return NULL
;
1086 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1087 return ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoMacroVocCFA
), 0);
1091 //==========================================================================
1095 // only in FORTH dictionary, including hidden words
1097 //==========================================================================
1098 static UForthWord
*ufoFindWordForth (const char *wname
) {
1099 if (!wname
|| wname
[0] == 0) return NULL
;
1100 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1101 UForthWord
*fw
= ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoForthVocCFA
), 1);
1102 if (fw
== NULL
) fw
= ufoFindWord(wname
);
1107 //==========================================================================
1109 // ufoFindWordCompiler
1111 //==========================================================================
1112 static UForthWord
*ufoFindWordCompiler (const char *wname
) {
1113 if (!wname
|| wname
[0] == 0) return NULL
;
1114 const uint32_t hash
= joaatHashBufCI(wname
, strlen(wname
));
1115 UForthWord
*fw
= ufoFindWordInVoc(wname
, hash
, UFO_GET_CFAPROC(ufoCompSuppVocCFA
), 1);
1116 if (fw
== NULL
) fw
= ufoFindWord(wname
);
1121 //==========================================================================
1123 // ufoAlwaysWordForth
1125 //==========================================================================
1126 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWordForth (const char *wname
) {
1127 UForthWord
*fw
= ufoFindWordForth(wname
);
1128 if (!fw
) ufoFatal("FORTH word `%s` not found", (wname
[0] ? wname
: "~"));
1133 //==========================================================================
1135 // ufoAlwaysWordCompiler
1137 //==========================================================================
1138 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWordCompiler (const char *wname
) {
1139 UForthWord
*fw
= ufoFindWordCompiler(wname
);
1140 if (!fw
) ufoFatal("COMPILER word `%s` not found", (wname
[0] ? wname
: "~"));
1145 //==========================================================================
1149 //==========================================================================
1150 UFO_FORCE_INLINE UForthWord
*ufoAlwaysWord (const char *wname
) {
1151 UForthWord
*fw
= ufoFindWord(wname
);
1152 if (!fw
) ufoFatal("word `%s` not found", (wname
[0] ? wname
: "~"));
1157 //==========================================================================
1161 //==========================================================================
1162 static UForthWord
*ufoNFind (uint32_t addr
, uint32_t count
) {
1165 if (count
> 127) return NULL
; // too long
1167 for (uint32_t n
= 0; n
< count
; ++n
) {
1168 const uint8_t ch
= ufoImgGetU8(addr
+n
)&0xffU
;
1169 if (!ch
) return NULL
; // word name cannot contain 0 byte
1170 wbuf
[n
] = (char)ch
; //toUpper((char)(ch));
1174 return ufoFindWord(wbuf
);
1178 //==========================================================================
1180 // ufoLoadNextLine_NativeMode
1182 // load next file line into TIB
1183 // always adds final '\n'
1185 //==========================================================================
1186 static void ufoLoadNextLine_NativeMode (int crossInclude
) {
1187 const uint8_t *text
= NULL
;
1189 ufoSetTIB(0); ufoSetIN(0);
1192 while (ufoInFile
&& done
== 0) {
1193 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
1194 // check for a newline
1195 // if there is no newline char at the end, the string was truncated
1196 ufoCurrFileLine
[510] = 0;
1197 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
1198 if (slen
== 0 || (ufoCurrFileLine
[slen
- 1u] != 13 && ufoCurrFileLine
[slen
- 1u] != 10)) {
1199 ufoFatal("input line too long");
1202 text
= (const uint8_t *)ufoCurrFileLine
;
1205 if (!crossInclude
) {
1206 if (ufoCondStLine
>= 0) {
1207 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1209 ufoFatal("unexpected end of text");
1218 text
= (const uint8_t *)ufoGetSrcLine(&fname
, &lnum
);
1220 if (ufoCondStLine
>= 0) {
1221 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1223 ufoFatal("unexpected end of text");
1225 ufoInFileLine
= lnum
;
1226 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1227 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1228 ufoInFileName
= strdup(fname
);
1229 setLastIncPath(ufoInFileName
);
1233 size_t sslen
= strlen((const char *)text
);
1234 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1235 if (sslen
> 510) ufoFatal("input line too long");
1236 if (text
!= (const void *)ufoCurrFileLine
) {
1237 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1239 ufoCurrFileLine
[sslen
+ 0] = 10;
1240 ufoCurrFileLine
[sslen
+ 1] = 0;
1242 #ifdef UFO_DEBUG_INLCUDE
1243 fprintf(stderr
, "NEXT-LINE: <%s>\n", ufoCurrFileLine
);
1246 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1247 uint8_t ch
= text
[dpos
];
1248 // replace bad chars, because why not
1249 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1250 ufoImgPutU32(dpos
, ch
);
1252 ufoImgPutU32((uint32_t)sslen
, 10);
1253 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1257 //==========================================================================
1261 //==========================================================================
1262 static void ufoLoadMacroLine (const char *line
, const char *fname
, int lnum
) {
1263 const uint8_t *text
= (const uint8_t *)line
;
1264 if (text
== NULL
) text
= (const uint8_t *)"";
1265 if (fname
== NULL
) fname
= "";
1267 ufoSetTIB(0); ufoSetIN(0);
1269 ufoInFileLine
= lnum
;
1270 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1271 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1272 ufoInFileName
= strdup(fname
);
1273 setLastIncPath(ufoInFileName
);
1276 size_t sslen
= strlen((const char *)text
);
1277 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1278 if (sslen
> 510) ufoFatal("input line too long");
1279 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1280 ufoCurrFileLine
[sslen
+ 0] = 10;
1281 ufoCurrFileLine
[sslen
+ 1] = 0;
1283 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1284 uint8_t ch
= text
[dpos
];
1285 // replace bad chars, because why not
1286 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1287 ufoImgPutU32(dpos
, ch
);
1289 ufoImgPutU32((uint32_t)sslen
, 10);
1290 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1294 //==========================================================================
1298 // load next file line into TIB
1299 // return zero on success, -1 on EOF, -2 on error
1301 //==========================================================================
1302 static void ufoLoadNextLine (int crossInclude
) {
1304 case UFO_MODE_NATIVE
:
1305 ufoLoadNextLine_NativeMode(crossInclude
);
1307 case UFO_MODE_MACRO
:
1308 if (ufoCondStLine
>= 0) {
1309 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1311 ufoFatal("unexpected end of input for FORTH asm macro");
1313 default: ufoFatal("wtf?! not properly inited!");
1318 // ////////////////////////////////////////////////////////////////////////// //
1319 // working with the stacks
1320 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("UFO data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
1321 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); --ufoSP
; }
1322 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("UFO data stack underflow"); } return ufoDStack
[--ufoSP
]; }
1323 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
1324 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
1325 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
1326 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
; }
1327 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
; }
1328 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
; }
1330 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
1331 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
1332 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
); }
1333 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
; }
1335 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("UFO return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
1336 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); --ufoRP
; }
1337 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[--ufoRP
]; }
1338 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
1339 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
1340 UFO_FORCE_INLINE
void ufoROver (void) { if (ufoRP
< 2u) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-2u]); }
1341 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
; }
1342 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
; }
1343 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
; }
1345 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
1348 // ////////////////////////////////////////////////////////////////////////// //
1349 #define UFWORD(name_) \
1350 static void ufoWord_##name_ (UForthWord *self)
1352 #define UFCALL(name_) ufoWord_##name_(NULL)
1353 #define UFCFA(name_) (&ufoWord_##name_)
1357 // ////////////////////////////////////////////////////////////////////////// //
1358 static void ufoDoForth (UForthWord
*self
) {
1360 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1361 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1364 if (self
->pfastart
!= self
->pfa
) {
1366 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1367 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1369 ufoPush(self
->pfastart
);
1375 //==========================================================================
1379 //==========================================================================
1380 static void ufoDoVoc (UForthWord
*self
) {
1381 ufoImgPutU32(ufoAddrContext
, self
->cfaidx
);
1385 //==========================================================================
1387 // ufoCompileWordCFA
1389 //==========================================================================
1390 UFO_FORCE_INLINE
void ufoCompileWordCFA (UForthWord
*fw
) {
1391 if (fw
== NULL
) ufoFatal("internal error in `ufoCompileWordCFA`");
1392 if (fw
->cfa
== NULL
|| FW_GET_CFAIDX(fw
) >= ufoCFAsUsed
) {
1393 ufoFatal("internal error in `ufoCompileWordCFA` (word: '%s')", fw
->name
);
1395 ufoImgEmitU32(fw
->cfaidx
);
1399 //==========================================================================
1401 // ufoCompileForthWord
1403 //==========================================================================
1404 UFO_FORCE_INLINE
void ufoCompileForthWord (const char *wname
) {
1405 ufoCompileWordCFA(ufoAlwaysWordForth(wname
));
1409 //==========================================================================
1411 // ufoCompileCompilerWord
1413 //==========================================================================
1414 UFO_FORCE_INLINE
void ufoCompileCompilerWord (const char *wname
) {
1415 ufoCompileWordCFA(ufoAlwaysWordCompiler(wname
));
1419 //==========================================================================
1421 // ufoCompileLiteral
1423 //==========================================================================
1424 static void ufoCompileLiteral (uint32_t value
) {
1425 ufoCompileCompilerWord("LIT");
1426 ufoImgEmitU32(value
);
1430 // ////////////////////////////////////////////////////////////////////////// //
1433 UFWORD(SP0_PUT
) { ufoSP
= 0; }
1437 UFWORD(RP0_PUT
) { ufoRP
= ufoRPTop
; }
1441 UFWORD(BASE
) { ufoPush(ufoBASEaddr
); }
1445 UFWORD(STATE
) { ufoPush(ufoSTATEaddr
); }
1448 // ( addr -- value32 )
1449 UFWORD(PEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)); }
1452 // ( addr -- value8 )
1453 UFWORD(CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU8(addr
)&0xffU
); }
1456 // ( addr -- value32 )
1457 UFWORD(WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)&0xffffU
); }
1460 // ( val32 addr -- )
1461 UFWORD(POKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU32(addr
, val
); }
1465 UFWORD(CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU8(addr
, val
&0xffU
); }
1468 // ( val32 addr -- )
1470 const uint32_t addr
= ufoPop();
1471 const uint32_t val
= ufoPop();
1472 ufoImgPutU32(addr
, val
&0xffffU
);
1477 // puts byte to native/zx dictionary, according to the current mode
1479 const uint32_t val
= ufoPop()&0xffU
;
1485 // puts byte to zx dictionary
1487 const uint32_t val
= ufoPop()&0xffU
;
1493 // puts uint/word to native/zx dictionary, according to the current mode
1495 const uint32_t val
= ufoPop();
1501 // puts word to zx dictionary
1503 const uint32_t val
= ufoPop();
1504 ufoZXEmitU16(val
&0xffffU
);
1508 // ( addr -- value8 )
1509 UFWORD(ZX_CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU8(addr
)); }
1513 UFWORD(ZX_CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU8(addr
, val
); }
1516 // ( addr -- value16 )
1517 UFWORD(ZX_WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU16(addr
)); }
1520 // ( val16 addr -- )
1521 UFWORD(ZX_WPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU16(addr
, val
); }
1525 UFWORD(ZX_RESERVEDQ
) {
1526 const uint32_t addr
= ufoPop();
1527 ufoPushBool(ufoZXGetReserved(addr
));
1532 UFWORD(ZX_RESERVEDS
) {
1533 const uint32_t addr
= ufoPop();
1534 const uint32_t flag
= ufoPop();
1535 ufoZXSetReserved(addr
, (flag
? 1 : 0));
1541 // is address a ZX Spectrum mmaped address?
1543 const uint32_t addr
= ufoPop();
1544 ufoPushBool(addr
&UFO_ZX_ADDR_BIT
);
1549 // convert address to ZX Spectrum mmaped address
1551 const uint32_t addr
= ufoPop();
1552 ufoPush((addr
&UFO_ZX_ADDR_MASK
)|UFO_ZX_ADDR_BIT
);
1557 // convert address to ZX Spectrum mmaped address
1559 if (ufoMode
== UFO_MODE_NATIVE
) {
1560 if (ufoIsCompiling()) {
1561 ufoCompileForthWord("(TOZX)");
1570 // convert address from ZX Spectrum mmaped address
1572 const uint32_t addr
= ufoPop();
1573 ufoPush(addr
&UFO_ZX_ADDR_MASK
);
1578 // convert address from ZX Spectrum mmaped address
1579 UFWORD(FROMZX_IMM
) {
1580 if (ufoMode
== UFO_MODE_NATIVE
) {
1581 if (ufoIsCompiling()) {
1582 ufoCompileForthWord("(FROMZX)");
1591 const uint32_t v
= ufoImgGetU32(ufoIP
++);
1597 ufoIP
= ufoImgGetU32(ufoIP
);
1600 // (TBRANCH) ( flag )
1603 ufoIP
= ufoImgGetU32(ufoIP
);
1609 // (0BRANCH) ( flag )
1612 ufoIP
= ufoImgGetU32(ufoIP
);
1619 // ( limit start -- | limit counter )
1620 // loops from start to limit-1
1627 // ( -- | limit counter )
1628 static void ufoPLoopCommon (int32_t add
) {
1629 const int32_t n
= (int32_t)ufoRPop();
1630 const int32_t lim
= (int32_t)ufoRPeek();
1631 const int32_t newn
= n
+add
;
1632 // this is how dsForth does it
1633 if ((newn
< 0 ? lim
-newn
: newn
-lim
) < 0) {
1635 ufoIP
= ufoImgGetU32(ufoIP
);
1643 // ( -- | limit counter )
1644 // loops from start to limit-1
1645 UFWORD(LOOP_PAREN
) {
1650 // ( n -- | limit counter )
1651 // loops from start to limit-1
1652 UFWORD(PLOOP_PAREN
) {
1653 const int32_t add
= (int32_t)ufoPop();
1654 ufoPLoopCommon(add
);
1661 const int32_t add = (int32_t)ufoPop();
1662 int32_t n = (int32_t)ufoRPop();
1663 const int32_t lim = (int32_t)ufoRPeek();
1664 if ((n < lim && n+add >= lim) || (n > lim && n+add <= lim)) {
1669 ufoIP = ufoImgGetU32(ufoIP);
1675 // ( counter -- | limit counter )
1677 ufoPush(ufoRPeek());
1681 // ( limit -- | limit counter )
1683 const uint32_t c
= ufoRPop();
1684 ufoPush(ufoRPeek());
1690 const uint32_t c0
= ufoRPop();
1691 const uint32_t c1
= ufoRPop();
1692 ufoPush(ufoRPeek());
1699 const uint32_t c0
= ufoRPop();
1700 const uint32_t c1
= ufoRPop();
1701 const uint32_t c2
= ufoRPop();
1702 ufoPush(ufoRPeek());
1709 //==========================================================================
1711 // ufoExecuteNativeWordInVM
1713 //==========================================================================
1714 UFO_FORCE_INLINE
void ufoExecuteNativeWordInVM (UForthWord
*fw
) {
1715 ufo_assert(fw
!= NULL
);
1716 if (fw
->cfa
== &ufoDoForth
) {
1717 const uint32_t oldRPTop
= ufoRPTop
;
1719 fw
->cfa(fw
); // this pushes IP, and may do other work
1721 ufoRPTop
= oldRPTop
;
1728 //==========================================================================
1732 //==========================================================================
1733 UFO_FORCE_INLINE
void ufoExecCFAIdxInVM (uint32_t cfa
) {
1734 if (cfa
& UFO_RS_CFA_BIT
) {
1735 cfa
&= UFO_RS_CFA_MASK
;
1736 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1737 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1738 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1739 ufoExecuteNativeWordInVM(fw
);
1741 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1746 //==========================================================================
1750 //==========================================================================
1751 UFO_FORCE_INLINE
void ufoExecCFAIdx (uint32_t cfa
) {
1752 if (cfa
& UFO_RS_CFA_BIT
) {
1753 cfa
&= UFO_RS_CFA_MASK
;
1754 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1755 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1756 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1759 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1765 UFWORD(EXECUTE
) { ufoExecCFAIdx(ufoPop()); }
1768 UFWORD(DUP
) { ufoDup(); }
1769 // ?DUP ( n -- n n ) | ( 0 -- 0 )
1770 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
1771 // 2DUP ( n0 n1 -- n0 n1 n0 n1 ) | ( 0 -- 0 )
1772 UFWORD(DDUP
) { ufo2Dup(); }
1774 UFWORD(DROP
) { ufoDrop(); }
1776 UFWORD(DDROP
) { ufo2Drop(); }
1777 // SWAP ( n0 n1 -- n1 n0 )
1778 UFWORD(SWAP
) { ufoSwap(); }
1779 // 2SWAP ( n0 n1 -- n1 n0 )
1780 UFWORD(DSWAP
) { ufo2Swap(); }
1781 // OVER ( n0 n1 -- n0 n1 n0 )
1782 UFWORD(OVER
) { ufoOver(); }
1783 // 2OVER ( n0 n1 -- n0 n1 n0 )
1784 UFWORD(DOVER
) { ufo2Over(); }
1785 // ROT ( n0 n1 n2 -- n1 n2 n0 )
1786 UFWORD(ROT
) { ufoRot(); }
1787 // NROT ( n0 n1 n2 -- n2 n0 n1 )
1788 UFWORD(NROT
) { ufoNRot(); }
1790 // RDUP ( n -- n n )
1791 UFWORD(RDUP
) { ufoRDup(); }
1793 UFWORD(RDROP
) { ufoRDrop(); }
1794 // RSWAP ( n0 n1 -- n1 n0 )
1795 UFWORD(RSWAP
) { ufoRSwap(); }
1796 // ROVER ( n0 n1 -- n0 n1 n0 )
1797 UFWORD(ROVER
) { ufoROver(); }
1798 // RROT ( n0 n1 n2 -- n1 n2 n0 )
1799 UFWORD(RROT
) { ufoRRot(); }
1800 // RNROT ( n0 n1 n2 -- n2 n0 n1 )
1801 UFWORD(RNROT
) { ufoRNRot(); }
1804 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
1805 // R> ( -- n | n-removed )
1806 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
1807 // R@ ( -- n | n-removed )
1808 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
1812 // ( src dest count -- )
1814 uint32_t count
= ufoPop();
1815 uint32_t dest
= ufoPop();
1816 uint32_t src
= ufoPop();
1817 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1823 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? ufoZXGetU8(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1824 if (dest
&UFO_ZX_ADDR_BIT
) ufoZXPutU8(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1829 // ( src dest count -- )
1830 UFWORD(CMOVE_BACK
) {
1831 uint32_t count
= ufoPop();
1832 uint32_t dest
= ufoPop();
1833 uint32_t src
= ufoPop();
1834 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1836 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? ufoZXGetU8(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1837 if (dest
&UFO_ZX_ADDR_BIT
) ufoZXPutU8(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1844 // ( src dest count -- )
1846 uint32_t count
= ufoPop();
1847 uint32_t dest
= ufoPop();
1848 uint32_t src
= ufoPop();
1852 if (dest
< src
) UFCALL(CMOVE_BACK
); else UFCALL(CMOVE_FWD
);
1857 // ( addr1 count1 addr2 count2 -- flag )
1859 uint32_t count2
= ufoPop();
1860 uint32_t addr2
= ufoPop();
1861 uint32_t count1
= ufoPop();
1862 uint32_t addr1
= ufoPop();
1863 if (count2
!= count1
) { ufoPushBool(0); return; }
1865 uint8_t c0
= ufoImgGetU8(addr1
++);
1866 uint8_t c1
= ufoImgGetU8(addr2
++);
1867 if (c0
!= c1
) { ufoPushBool(0); return; }
1873 // ( addr1 count1 addr2 count2 -- flag )
1875 uint32_t count2
= ufoPop();
1876 uint32_t addr2
= ufoPop();
1877 uint32_t count1
= ufoPop();
1878 uint32_t addr1
= ufoPop();
1879 if (count2
!= count1
) { ufoPushBool(0); return; }
1881 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1882 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1883 if (c0
!= c1
) { ufoPushBool(0); return; }
1889 // ( addr1 count1 addr2 count2 -- signed-flag )
1891 uint32_t count2
= ufoPop();
1892 uint32_t addr2
= ufoPop();
1893 uint32_t count1
= ufoPop();
1894 uint32_t addr1
= ufoPop();
1895 while (count1
!= 0 && count2
!= 0) {
1896 uint8_t c0
= ufoImgGetU8(addr1
++);
1897 uint8_t c1
= ufoImgGetU8(addr2
++);
1899 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1903 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1904 else if (count2
== 0) ufoPush(1u);
1905 else __builtin_trap();
1909 // ( addr1 count1 addr2 count2 -- flag )
1911 uint32_t count2
= ufoPop();
1912 uint32_t addr2
= ufoPop();
1913 uint32_t count1
= ufoPop();
1914 uint32_t addr1
= ufoPop();
1915 while (count1
!= 0 && count2
!= 0) {
1916 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1917 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1919 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1923 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1924 else if (count2
== 0) ufoPush(1u);
1925 else __builtin_trap();
1929 // ////////////////////////////////////////////////////////////////////////// //
1930 // text input buffer parsing
1932 //==========================================================================
1936 //==========================================================================
1937 UFO_FORCE_INLINE
uint32_t ufoTibCharAddr (void) {
1938 return ufoGetTIB() + ufoGetIN();
1942 //==========================================================================
1946 //==========================================================================
1947 UFO_FORCE_INLINE
uint8_t ufoPeekInChar (void) {
1948 return ufoImgGetU8(ufoTibCharAddr());
1952 //==========================================================================
1956 //==========================================================================
1957 UFO_FORCE_INLINE
uint8_t ufoGetInChar (void) {
1958 const uint32_t tib
= ufoGetTIB();
1959 const uint32_t in
= ufoGetIN();
1960 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1961 if (ch
!= 0) ufoSetIN(in
+ 1);
1966 //==========================================================================
1968 // ufoGetInCharAndAddr
1970 //==========================================================================
1971 UFO_FORCE_INLINE
uint8_t ufoGetInCharAndAddr (uint32_t *addr
) {
1972 const uint32_t tib
= ufoGetTIB();
1973 const uint32_t in
= ufoGetIN();
1975 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1976 if (ch
!= 0) ufoSetIN(in
+ 1);
1983 UFWORD(TIB_ADVANCE_LINE
) {
1989 UFWORD(TIB_PEEKCH
) {
1990 ufoPush(ufoPeekInChar());
1995 UFWORD(TIB_SKIPCH
) {
1996 (void)ufoGetInChar();
2002 ufoPush(ufoGetInChar());
2007 UFWORD(GET_IN_ADDR
) { ufoPush(ufoAddrIN
); }
2011 UFWORD(GET_TIB_ADDR
) { ufoPush(ufoAddrTIB
); }
2014 // ( -- size-in-cells )
2015 UFWORD(GET_TIB_SIZE
) { ufoPush(ufoTIBAreaSize
); }
2021 ufoPush(ufoImageUsed
);
2025 // ( -- n+UFO_PAD_OFFSET,aligned to 1kb )
2027 ufoPush(ufoPadAddr());
2033 uint32_t addr
= ufoPop();
2034 uint32_t len
= ufoImgGetCounter(addr
);
2040 //==========================================================================
2042 // ufoWordIsGoodDelim
2044 //==========================================================================
2045 UFO_FORCE_INLINE
int ufoWordIsGoodDelim (uint32_t ch
, uint32_t delim
) {
2046 return (ch
== delim
|| (delim
== 32 && ch
<= 32));
2051 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
2052 // does base TIB parsing; never copies anything.
2053 // as our reader is line-based, returns FALSE on EOL.
2054 // EOL is detected after skipping leading delimiters.
2055 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2056 // trailing delimiter is always skipped.
2058 const uint32_t skipLeading
= ufoPop();
2059 uint32_t delim
= ufoPop();
2060 uint32_t addr
= 0, count
;
2063 if (delim
> 255) ufoFatal("invalid delimiter char");
2066 #ifdef UFO_DEBUG_PARSE
2067 fprintf(stderr
, "*** (PARSE): delim=%u(%c); skip=%u\n", delim
, (char)delim
, skipLeading
);
2069 ch
= ufoGetInCharAndAddr(&addr
);
2070 #ifdef UFO_DEBUG_PARSE
2071 fprintf(stderr
, " FCH: %u(%c)\n", ch
, (ch
> 32 && ch
< 127 ? (char)ch
: '?'));
2073 // skip leading delimiters
2074 while (ch
!= 0 && skipLeading
&& ufoWordIsGoodDelim(ch
, delim
)) ch
= ufoGetInCharAndAddr(&addr
);
2077 #ifdef UFO_DEBUG_PARSE
2078 fprintf(stderr
, " COLLECT: %u\n", ch
);
2081 while (ch
!= 0 && !ufoWordIsGoodDelim(ch
, delim
)) { count
+= 1; ch
= ufoGetInChar(); }
2082 #ifdef UFO_DEBUG_PARSE
2083 fprintf(stderr
, " COLLECTED: ch=%u; count=%u; addr=%u\n", ch
, count
, addr
);
2089 #ifdef UFO_DEBUG_PARSE
2090 fprintf(stderr
, " EOL!\n");
2095 // skip the whole line
2096 while (ufoGetInChar() != 0) {}
2102 // ( delim skip-leading-delim? -- here TRUE / FALSE )
2103 // parse word, copy it to HERE as counted string.
2104 // adds trailing zero after the string, but doesn't include it in count.
2105 // doesn't advance line.
2106 UFWORD(PAR_WORD_OR_PARSE
) {
2109 uint32_t count
= ufoPop();
2110 uint32_t src
= ufoPop();
2112 uint32_t dest
= ufoPop();
2113 ufoImgPutU32(dest
, count
);
2114 for (uint32_t f
= 0; f
< count
; f
+= 1) {
2115 ufoImgPutU8(dest
+ f
+ 1, ufoImgGetU8(src
+ f
));
2117 ufoImgPutU32(dest
+ count
+ 1, 0); // put trailing zero, just in case
2126 // ( delim -- here )
2127 // parse word, copy it to HERE as counted string.
2128 // adds trailing zero after the string, but doesn't include it in count.
2129 // doesn't advance line.
2130 // return empty string on EOL.
2133 UFCALL(PAR_WORD_OR_PARSE
);
2136 uint32_t dest
= ufoPop();
2137 ufoImgPutU32(dest
, 0); // counter
2138 ufoImgPutU32(dest
+ 1, 0); // trailing zero
2144 // ( delim -- addr count TRUE / FALSE )
2145 // parse word w/o skipping delimiters, copy it to HERE as counted string.
2146 // adds trailing zero after the string, but doesn't include it in count.
2147 // doesn't advance line.
2148 UFWORD(PARSE_TO_HERE
) {
2150 UFCALL(PAR_WORD_OR_PARSE
);
2160 // ( -- addr count )
2161 // parse with skipping leading blanks. doesn't copy anything.
2162 // return empty string on EOL.
2163 UFWORD(PARSE_NAME
) {
2164 ufoPush(32); ufoPushBool(1);
2167 ufoPush(ufoTibCharAddr());
2173 // ( delim -- addr count TRUE / FALSE )
2174 // parse without skipping delimiters; never copies anything.
2175 // as our reader is line-based, returns FALSE on EOL.
2176 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2177 // trailing delimiter is always skipped.
2184 //==========================================================================
2186 // ufoPopStrLitToTempBuf
2188 //==========================================================================
2189 static void ufoPopStrLitToTempBuf (void) {
2190 uint32_t count
= ufoPop();
2191 uint32_t addr
= ufoPop();
2192 if (count
== 0) ufoFatal("unexpected end of line");
2193 ufo_assert(count
< (uint32_t)sizeof(ufoTempCharBuf
));
2195 while (dpos
!= count
) {
2196 ufoTempCharBuf
[dpos
] = ufoImgGetU8(addr
+ dpos
);
2199 ufoTempCharBuf
[dpos
] = 0;
2203 //==========================================================================
2205 // ufoParseNameToTempBuf
2207 // parse forth word name from TIB, put it to `ufoTempCharBuf`.
2208 // on EOL, `ufoTempCharBuf` will be an empty string.
2210 //==========================================================================
2211 static void ufoParseNameToTempBuf (void) {
2213 if (ufoPeek() == 0) ufoFatal("word name expected");
2214 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2215 ufoPopStrLitToTempBuf();
2219 //==========================================================================
2221 // ufoParseNameToTempBufEmptyOk
2223 //==========================================================================
2224 static void ufoParseNameToTempBufEmptyOk (void) {
2226 if (ufoPeek() == 0) {
2227 ufoTempCharBuf
[0] = 0;
2229 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2230 ufoPopStrLitToTempBuf();
2235 //==========================================================================
2237 // ufoPutTempStrLiteral
2239 // puts counted string literal to PAD
2240 // returns VM address of counted string
2242 //==========================================================================
2243 static uint32_t ufoPutTempStrLiteral (const char *s
) {
2245 const size_t slen
= strlen(s
);
2246 if (slen
> 1024*1024) ufoFatal("temp string too long");
2247 uint32_t dest
= ufoPadAddr();
2248 ufoImgPutU32(dest
, (uint32_t)slen
);
2249 for (size_t f
= 0; f
<= slen
; ++f
) {
2250 ufoImgPutU32(dest
+ f
+ 1, (uint8_t)(s
[f
]&0xffU
));
2256 // ////////////////////////////////////////////////////////////////////////// //
2262 uint32_t ch
= ufoPop()&0xffU
;
2263 if (ch
< 32 || ch
== 127) {
2264 if (ch
!= 10 && ch
!= 13 && ch
!= 9) { printf("?"); return; }
2266 ufoLastEmitWasCR
= (ch
== 10);
2267 if (ch
== 10) printf("\n"); else printf("%c", (char)ch
);
2273 uint32_t ch
= ufoPop()&0xffU
;
2274 printf("%c", (ch
< 32 || ch
== 127 ? '?' : (char)ch
));
2275 ufoLastEmitWasCR
= 0;
2282 ufoLastEmitWasCR
= 1;
2289 ufoLastEmitWasCR
= 0;
2295 int32_t n
= (int32_t)ufoPop();
2296 while (n
-- > 0) printf(" ");
2297 ufoLastEmitWasCR
= 0;
2303 if (!ufoLastEmitWasCR
) {
2305 ufoLastEmitWasCR
= 1;
2312 ufoPushBool(ufoLastEmitWasCR
);
2318 ufoLastEmitWasCR
= !!ufoPop();
2322 // ( addr count -- )
2324 int32_t count
= (int32_t)ufoPop();
2325 uint32_t addr
= ufoPop();
2326 while (count
-- > 0) {
2327 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2334 // ( addr count -- )
2336 int32_t count
= (int32_t)ufoPop();
2337 uint32_t addr
= ufoPop();
2338 while (count
-- > 0) {
2339 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2346 UFWORD(STRQ_PAREN
) {
2347 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2349 if (count
> 0x7fffffffU
) ufoPush(0); else ufoPush(count
);
2354 UFWORD(STRDOTQ_PAREN
) {
2355 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2363 //==========================================================================
2365 // ufoNTWordAddrCount
2367 //==========================================================================
2368 static UForthWord
*ufoNTWordAddrCount (void) {
2369 uint32_t count
= ufoPop();
2370 uint32_t addr
= ufoPop();
2371 UForthWord
*fw
= ufoNFind(addr
, count
);
2373 UFCALL(SPACE
); ufoPush(addr
); ufoPush(count
); UFCALL(XTYPE
);
2374 printf(" -- wut?\n"); ufoLastEmitWasCR
= 1;
2375 ufoFatal("unknown UFO word");
2381 // ////////////////////////////////////////////////////////////////////////// //
2384 //==========================================================================
2388 //==========================================================================
2389 static char *ufoPrintNumber (uint32_t v
, int sign
) {
2390 static char buf
[64];
2391 size_t bufpos
= sizeof(buf
);
2393 int64_t n
= (sign
? (int64_t)(int32_t)v
: (int64_t)(uint32_t)v
);
2394 const char sch
= (n
< 0 ? '-' : 0);
2396 int base
= ufoImgGetU32(ufoBASEaddr
);
2397 if (base
< 2 || base
> 36) { snprintf(buf
, sizeof(buf
), "%s", "invalid-base"); return buf
; }
2399 if (bufpos
== 0) ufoFatal("number too long");
2400 char ch
= '0'+(char)(n
%base
);
2401 if (ch
> '9') ch
+= 7;
2403 } while ((n
/= base
) != 0);
2404 if (bufpos
!= 0 && sch
) buf
[--bufpos
] = sch
;
2412 int32_t v
= (int32_t)ufoPop();
2413 printf("%s ", ufoPrintNumber(v
, 1));
2419 uint32_t v
= ufoPop();
2420 printf("%s ", ufoPrintNumber(v
, 0));
2426 int32_t wdt
= (int32_t)ufoPop();
2427 int32_t v
= (int32_t)ufoPop();
2428 char *s
= ufoPrintNumber(v
, 1);
2429 int32_t slen
= (int32_t)strlen(s
);
2430 while (slen
< wdt
) { printf(" "); ++slen
; }
2437 int32_t wdt
= (int32_t)ufoPop();
2438 int32_t v
= (int32_t)ufoPop();
2439 char *s
= ufoPrintNumber(v
, 0);
2440 int32_t slen
= (int32_t)strlen(s
);
2441 while (slen
< wdt
) { printf(" "); ++slen
; }
2446 // ////////////////////////////////////////////////////////////////////////// //
2452 const uint32_t a
= ufoPop();
2459 const uint32_t b
= ufoPop();
2460 const uint32_t a
= ufoPop();
2467 const uint32_t b
= ufoPop();
2468 const uint32_t a
= ufoPop();
2475 const int32_t b
= (int32_t)ufoPop();
2476 const int32_t a
= (int32_t)ufoPop();
2477 ufoPush((uint32_t)(a
*b
));
2483 const uint32_t b
= ufoPop();
2484 const uint32_t a
= ufoPop();
2485 ufoPush((uint32_t)(a
*b
));
2491 const int32_t b
= (int32_t)ufoPop();
2492 const int32_t a
= (int32_t)ufoPop();
2493 if (b
== 0) ufoFatal("UFO division by zero");
2494 ufoPush((uint32_t)(a
/b
));
2500 const uint32_t b
= ufoPop();
2501 const uint32_t a
= ufoPop();
2502 if (b
== 0) ufoFatal("UFO division by zero");
2503 ufoPush((uint32_t)(a
/b
));
2509 const int32_t b
= (int32_t)ufoPop();
2510 const int32_t a
= (int32_t)ufoPop();
2511 if (b
== 0) ufoFatal("UFO division by zero");
2512 ufoPush((uint32_t)(a
%b
));
2518 const uint32_t b
= ufoPop();
2519 const uint32_t a
= ufoPop();
2520 if (b
== 0) ufoFatal("UFO division by zero");
2521 ufoPush((uint32_t)(a
%b
));
2525 // ( a b -- a/b, a%b )
2527 const int32_t b
= (int32_t)ufoPop();
2528 const int32_t a
= (int32_t)ufoPop();
2529 if (b
== 0) ufoFatal("UFO division by zero");
2530 ufoPush((uint32_t)(a
/b
));
2531 ufoPush((uint32_t)(a
%b
));
2535 // ( a b -- a/b, a%b )
2537 const uint32_t b
= ufoPop();
2538 const uint32_t a
= ufoPop();
2539 if (b
== 0) ufoFatal("UFO division by zero");
2540 ufoPush((uint32_t)(a
/b
));
2541 ufoPush((uint32_t)(a
%b
));
2545 // ////////////////////////////////////////////////////////////////////////// //
2551 const int32_t b
= (int32_t)ufoPop();
2552 const int32_t a
= (int32_t)ufoPop();
2559 const int32_t b
= (int32_t)ufoPop();
2560 const int32_t a
= (int32_t)ufoPop();
2567 const int32_t b
= (int32_t)ufoPop();
2568 const int32_t a
= (int32_t)ufoPop();
2569 ufoPushBool(a
<= b
);
2575 const int32_t b
= (int32_t)ufoPop();
2576 const int32_t a
= (int32_t)ufoPop();
2577 ufoPushBool(a
>= b
);
2583 const uint32_t b
= ufoPop();
2584 const uint32_t a
= ufoPop();
2591 const uint32_t b
= ufoPop();
2592 const uint32_t a
= ufoPop();
2599 const uint32_t b
= ufoPop();
2600 const uint32_t a
= ufoPop();
2601 ufoPushBool(a
<= b
);
2607 const uint32_t b
= ufoPop();
2608 const uint32_t a
= ufoPop();
2609 ufoPushBool(a
>= b
);
2615 const uint32_t b
= ufoPop();
2616 const uint32_t a
= ufoPop();
2617 ufoPushBool(a
== b
);
2623 const uint32_t b
= ufoPop();
2624 const uint32_t a
= ufoPop();
2625 ufoPushBool(a
!= b
);
2629 // ( value a b -- value>=a&&value<b )
2631 const int32_t value
= (int32_t)ufoPop();
2632 const int32_t b
= (int32_t)ufoPop();
2633 const int32_t a
= (int32_t)ufoPop();
2634 ufoPushBool(value
>= a
&& value
< b
);
2638 // ( value a b -- value>=a&&value<b )
2640 const uint32_t value
= ufoPop();
2641 const uint32_t b
= ufoPop();
2642 const uint32_t a
= ufoPop();
2643 ufoPushBool(value
>= a
&& value
< b
);
2647 // ( value a b -- value>=a&&value<=b )
2650 const uint32_t value
= ufoPop();
2651 const uint32_t b
= ufoPop();
2652 const uint32_t a
= ufoPop();
2653 ufoPushBool(value
>= a
&& value
<= b
);
2659 const uint32_t a
= ufoPop();
2666 const uint32_t a
= ufoPop();
2673 const uint32_t b
= ufoPop();
2674 const uint32_t a
= ufoPop();
2675 ufoPushBool(a
&& b
);
2681 const uint32_t b
= ufoPop();
2682 const uint32_t a
= ufoPop();
2683 ufoPushBool(a
|| b
);
2689 const uint32_t b
= ufoPop();
2690 const uint32_t a
= ufoPop();
2697 const uint32_t b
= ufoPop();
2698 const uint32_t a
= ufoPop();
2705 const uint32_t b
= ufoPop();
2706 const uint32_t a
= ufoPop();
2713 const uint32_t a
= ufoPop();
2717 UFWORD(ONEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+1u); }
2718 UFWORD(ONEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-1u); }
2719 UFWORD(TWOPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+2u); }
2720 UFWORD(TWOMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-2u); }
2721 UFWORD(THREEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+3u); }
2722 UFWORD(THREEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-3u); }
2723 UFWORD(FOURPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+4u); }
2724 UFWORD(FOURMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-4u); }
2725 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
*2u); }
2726 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
/2u); }
2728 UFWORD(LSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
<<c
); ufoPush(n
); }
2729 UFWORD(RSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
>>c
); ufoPush(n
); }
2733 // ////////////////////////////////////////////////////////////////////////// //
2739 if (ufoIsCompiling()) {
2740 ufoCompileLiteral(ufoPop());
2745 // ( addr count -- addr count )
2746 UFWORD(STR_UNESCAPE
) {
2747 uint32_t count
= (int32_t)ufoPop();
2748 const uint32_t addr
= ufoPeek();
2749 const uint32_t eaddr
= addr
+ count
;
2750 uint32_t caddr
= addr
;
2751 uint32_t daddr
= addr
;
2752 while (caddr
!= eaddr
) {
2753 uint8_t ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2754 if (ch
== '\\' && caddr
!= eaddr
) {
2755 ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2757 case 'r': ch
= '\r'; break;
2758 case 'n': ch
= '\n'; break;
2759 case 't': ch
= '\t'; break;
2760 case 'e': ch
= '\x1b'; break;
2761 case '`': ch
= '"'; break; // special escape to insert double-quoted
2762 case '"': ch
= '"'; break;
2763 case '\'': ch
= '\''; break;
2764 case '\\': ch
= '\\'; break;
2766 if (eaddr
- daddr
>= 1) {
2767 const int dg0
= digitInBase((char)(ufoImgGetU8(caddr
+ 1)), 16);
2768 if (dg0
< 0) ufoFatal("invalid hex string escape");
2769 if (eaddr
- daddr
>= 2) {
2770 const int dg1
= digitInBase((char)(ufoImgGetU8(caddr
+ 2)), 16);
2771 if (dg1
< 0) ufoFatal("invalid hex string escape");
2772 ch
= (uint8_t)(dg0
* 16 + dg1
);
2779 ufoFatal("invalid hex string escape");
2782 default: ufoFatal("invalid string escape");
2785 if (caddr
!= daddr
) ufoImgPutU32(daddr
, ch
);
2788 if (daddr
< eaddr
) ufoImgPutU32(daddr
, 0);
2789 ufoPush(daddr
- addr
);
2793 // I:( addr count -- addr count )
2794 // R:( -- addr count )
2795 // C:( addr count -- )
2796 // addr *MUST* be HERE+1
2797 UFWORD(STRLITERAL
) {
2798 UFCALL(STR_UNESCAPE
);
2799 if (ufoIsCompiling()) {
2800 uint32_t count
= ufoPop();
2801 uint32_t addr
= ufoPop();
2803 if (count
> 0xffffU
) ufoFatal("UFO string too long");
2804 if (addr
- 1u != ufoImageUsed
) {
2805 ufoFatal("invalid call to UFO word 'STRLITERAL'");
2807 ufoImgPutU32(addr
- 1u, count
);
2808 ufoImageUsed
+= count
+ 1u;
2814 // ( -- addr count )
2816 if (ufoIsCompiling()) ufoCompileCompilerWord("(\")");
2817 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2820 if (ufoIsInterpreting()) {
2822 uint32_t dest
= ufoPadAddr();
2823 uint32_t count
= ufoPop();
2824 uint32_t src
= ufoPop();
2825 if (dest
>= src
&& dest
<= src
+ count
) ufoFatal("something's wrong!");
2826 if (count
> 1022) ufoFatal("UFO string too long");
2827 ufoImgPutU32(dest
, count
);
2828 for (uint32_t n
= 0; n
< count
; ++n
) ufoImgPutU32(dest
+ n
+ 1, ufoImgGetU32(src
+ n
));
2829 ufoImgPutU32(dest
+ count
+ 1, 0);
2834 ufoFatal("string literal expected");
2841 if (ufoIsCompiling()) ufoCompileCompilerWord("(.\")");
2842 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2845 if (ufoIsInterpreting()) {
2849 ufoFatal("string literal expected");
2854 // ////////////////////////////////////////////////////////////////////////// //
2858 //==========================================================================
2860 // ufoGetInCharAutoLineAdvance
2862 //==========================================================================
2863 static uint8_t ufoGetInCharAutoLineAdvance (void) {
2866 ch
= ufoGetInChar();
2867 if (ch
== 0) ufoLoadNextLine(0);
2874 UFWORD(COMMENTEOL
) {
2875 // just skip the whole line
2876 while (ufoGetInChar() != 0) {}
2880 UFWORD(COMMENTPAREN
) {
2882 do { ch
= ufoGetInCharAutoLineAdvance(); } while (ch
!= ')');
2885 // "(*" multiline comment
2887 uint32_t prevch
= 0, ch
= 0;
2890 ch
= ufoGetInCharAutoLineAdvance();
2891 } while (prevch
!= '*' || ch
!= ')');
2894 // "((" multiline comment
2895 UFWORD(COMMENTML_NESTED
) {
2897 uint32_t prevch
= 0, ch
= 0;
2900 ch
= ufoGetInCharAutoLineAdvance();
2901 if (prevch
== '(' && ch
== '(') { ch
= 0; level
+= 1; }
2902 else if (prevch
== ')' && ch
== ')') { ch
= 0; level
-= 1; }
2903 } while (level
!= 0);
2907 // NFIND ( addr count -- cfa TRUE | 0 )
2908 // find native/zx word
2909 // onlynativeimmflag:
2910 // 0: look for ZX word only if native word not found
2911 // !0: look for ZX word only if native word not found, or if it is not immediate
2912 // 666: prefer ZX words (used in `COMPILE`)
2913 // returned ZX CFA has `UFO_ZX_ADDR_BIT` set
2916 // look for native word
2917 // if there is none, look for zx word
2919 // look for native word
2920 // STATE == 0: (interpreting)
2921 // if there is none, look for zx word
2922 // STATE != 0: (compiling)
2923 // if no native word, or native word is not immediate, look for zx word
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 // more compiler words
3116 if (ufoIsCompiling()) ufoFatal("expecting execution mode");
3121 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3125 // ( ocond cond -- )
3127 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3128 const uint32_t cond
= ufoPop();
3129 const uint32_t ocond
= ufoPop();
3130 if (cond
!= ocond
) ufoFatal("unbalanced structured code");
3134 UFWORD(COMPILE_IMM
) {
3135 if (ufoIsInterpreting()) ufoFatal("cannot call `COMPILE` from interpreter");
3138 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3140 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3141 ufoCompileLiteral(cfa
);
3142 ufoCompileForthWord(",");
3144 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3145 printf(" -- wut?"); UFCALL(CR
);
3146 ufoFatal("unknown word");
3149 ufoFatal("word name expected");
3154 UFWORD(XCOMPILE_IMM
) {
3155 if (ufoIsInterpreting()) ufoFatal("cannot call `[COMPILE]` from interpreter");
3158 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3160 UForthWord
*fw
= UFO_GET_NATIVE_CFA(ufoPop());
3161 ufoCompileWordCFA(fw
);
3163 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3164 printf(" -- wut?"); UFCALL(CR
);
3165 ufoFatal("unknown word");
3168 ufoFatal("word name expected");
3176 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3178 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3179 if (ufoIsCompiling()) {
3180 ufoCompileLiteral(cfa
);
3185 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3186 printf(" -- wut?"); UFCALL(CR
);
3187 ufoFatal("unknown word");
3190 ufoFatal("word name expected");
3195 UFWORD(XTICKPFA_IMM
) {
3198 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3200 uint32_t cfa
= ufoPop();
3201 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3202 if (ufoIsCompiling()) {
3203 ufoCompileLiteral(fw
->pfa
);
3208 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3209 printf(" -- wut?"); UFCALL(CR
);
3210 ufoFatal("unknown word");
3213 ufoFatal("word name expected");
3223 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3225 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3228 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3229 printf(" -- wut?"); UFCALL(CR
);
3230 ufoFatal("unknown word");
3233 ufoFatal("word name expected");
3238 UFWORD(TICKPFA_IMM
) {
3242 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3244 uint32_t cfa
= ufoPop();
3245 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3248 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3249 printf(" -- wut?"); UFCALL(CR
);
3250 ufoFatal("unknown word");
3253 ufoFatal("word name expected");
3261 ufoImgEmitU32(ufoPop());
3266 // calculate the forward branch offset from addr to HERE and put it into the addr
3269 const uint32_t here
= ufoPop();
3270 const uint32_t addr
= ufoPop();
3271 ufoImgPutU32(addr
, here
);
3275 // ////////////////////////////////////////////////////////////////////////// //
3278 static int ufoIsLocalsEnter (UForthWord
*ww
) {
3280 if (ww
!= NULL
&& ww
->pfa
+ 1 < ufoImageUsed
) {
3281 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3282 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3283 res
= (w
== fw
->cfaidx
);
3289 //==========================================================================
3293 //==========================================================================
3294 static uint32_t ufoPrepareEnter (UForthWord
*ww
) {
3296 if (!ufoIsCompiling()) ufoFatal("compile mode expected");
3297 if (ufoInColon
!= 1) ufoFatal("must be in a word definition");
3298 if (ww
->cfa
!= NULL
) ufoFatal("wutafuck?");
3299 if (ww
->pfa
== ufoImageUsed
) {
3300 ufoCompileCompilerWord("(L-ENTER)");
3303 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3304 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3305 if (w
!= fw
->cfaidx
) ufoFatal("arg/local definition must be the first word");
3306 res
= ufoImgGetU32(ww
->pfa
+ 1);
3312 //==========================================================================
3316 //==========================================================================
3317 UFO_FORCE_INLINE
void ufoUpdateEnter (UForthWord
*ww
, uint32_t val
) {
3318 ufoImgPutU32(ww
->pfa
+ 1, val
);
3325 if (ufoRP
< ufoRPTop
) ufoFatal("return stack undeflow in (EXIT)");
3326 ufoStopVM
= (ufoRP
== ufoRPTop
);
3331 UFWORD(PAR_LENTER
) {
3332 // low byte of loccount is total number of locals
3333 // higt byte is the number of args
3334 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 1;
3335 uint32_t acount
= (lcount
>> 8)&0xff;
3337 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3338 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3339 ufoFatal("out of locals stack");
3342 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3343 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3344 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3345 ufoLBP
= newbp
; ufoLP
+= lcount
;
3348 while (newbp
!= ufoLBP
) {
3349 ufoLStack
[newbp
] = ufoPop();
3355 UFWORD(PAR_LLEAVE
) {
3356 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3357 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3359 ufoLBP
= ufoLStack
[ufoLBP
];
3364 if (ufoIsInterpreting()) ufoFatal("EXIT in interpreter?");
3365 if (ufoInColon
== 1) {
3366 if (ufoColonWord
->cfa
!= NULL
) ufoFatal("invalid EXIT");
3367 if (ufoIsLocalsEnter(ufoColonWord
)) ufoCompileCompilerWord("(L-LEAVE)");
3369 ufoCompileCompilerWord("(EXIT)");
3376 ufoCompileCompilerWord("(0BRANCH)");
3379 ufoPush(UFO_QPAIRS_IF
);
3385 ufoCompileCompilerWord("(TBRANCH)");
3388 ufoPush(UFO_QPAIRS_IF
);
3394 ufoPush(UFO_QPAIRS_IF
);
3402 ufoPush(UFO_QPAIRS_IF
);
3404 ufoCompileCompilerWord("(BRANCH)");
3408 ufoPush(UFO_QPAIRS_IF
);
3410 ufoPush(UFO_QPAIRS_IF
);
3417 ufoCompileCompilerWord("(DO)");
3419 ufoPush(UFO_QPAIRS_DO
);
3425 ufoPush(UFO_QPAIRS_DO
);
3427 ufoCompileCompilerWord("(LOOP)");
3434 ufoPush(UFO_QPAIRS_DO
);
3436 ufoCompileCompilerWord("(+LOOP)");
3445 ufoPush(UFO_QPAIRS_BEGIN
);
3448 static void ufoCommonUntil (const char *bword
) {
3451 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3455 ufoPush(UFO_QPAIRS_BEGIN
);
3459 // first is begin addr
3460 ufoCompileCompilerWord(bword
);
3463 // then jumps to the end
3464 while (ufoPeek() != ~0U) { UFCALL(COMP_FWD
); }
3470 UFWORD(UNTIL
) { ufoCommonUntil("(0BRANCH)"); }
3473 UFWORD(NOT_UNTIL
) { ufoCommonUntil("(TBRANCH)"); }
3476 UFWORD(AGAIN
) { ufoCommonUntil("(BRANCH)"); }
3478 static void ufoCommonWhile (int normal
) {
3481 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3485 ufoPush(UFO_QPAIRS_BEGIN
);
3490 ufoCompileCompilerWord(normal
? "(0BRANCH)" : "(TBRANCH)");
3494 ufoPush(UFO_QPAIRS_WHILE
);
3498 UFWORD(WHILE
) { ufoCommonWhile(1); }
3501 UFWORD(NOT_WHILE
) { ufoCommonWhile(0); }
3504 //==========================================================================
3508 //==========================================================================
3509 static void ufoXOF (const char *cmpwname
, int doswap
) {
3511 ufoPush(UFO_QPAIRS_CASE
);
3513 ufoCompileForthWord("OVER");
3514 if (doswap
) ufoCompileForthWord("SWAP");
3515 ufoCompileForthWord(cmpwname
);
3516 ufoCompileCompilerWord("(0BRANCH)");
3520 ufoCompileForthWord("DROP");
3521 ufoPush(UFO_QPAIRS_OF
);
3528 ufoPush(ufoCSP
); ufoCSP
= ufoSP
; //CSP @ !CSP
3529 ufoPush(UFO_QPAIRS_CASE
);
3545 ufoPush(UFO_QPAIRS_OF
);
3547 ufoCompileCompilerWord("(BRANCH)");
3552 ufoPush(UFO_QPAIRS_IF
);
3554 ufoPush(UFO_QPAIRS_CASE
);
3560 ufoPush(UFO_QPAIRS_CASE
);
3562 ufoPush(UFO_QPAIRS_OTHER
);
3568 if (ufoPeek() != UFO_QPAIRS_OTHER
) {
3569 ufoPush(UFO_QPAIRS_CASE
);
3571 ufoCompileForthWord("DROP");
3575 //fprintf(stderr, "SP=%u; csp=%u\n", ufoSP, ufoCSP);
3576 if (ufoSP
< ufoCSP
) ufoFatal("ENDCASE compiler error");
3577 while (ufoSP
> ufoCSP
) {
3578 ufoPush(UFO_QPAIRS_IF
);
3581 ufoCSP
= ufoPop(); //CSP !
3585 // ////////////////////////////////////////////////////////////////////////// //
3586 // define Forth words
3589 //==========================================================================
3593 //==========================================================================
3594 static UForthWord
*ufoRegisterWord (const char *wname
, void (*cfa
) (UForthWord
*self
),
3597 if (!wname
) wname
= "";
3598 if (strlen(wname
) > 127) ufoFatal("too long word name '%s'", wname
);
3599 UForthWord
*fw
= ufoFindWord(wname
);
3601 if (UFW_IS_PROT(fw
)) {
3602 ufoFatal("cannot redefine protected word '%s'", wname
);
3604 printf("redefined word '%s'.\n", wname
); ufoLastEmitWasCR
= 1;
3606 fw
= calloc(1, sizeof(UForthWord
));
3607 fw
->name
= strdup(wname
);
3608 #ifdef UFO_UPPERCASE_DICT_WORDS
3609 for (char *s
= fw
->name
; *s
; ++s
) *s
= toUpper(*s
);
3612 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3614 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3615 fw
->pfastart
= ufoImageUsed
;
3617 ufoLinkWordToDict(fw
);
3618 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3619 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3620 //fprintf(stderr, "***NEW WORD #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
3625 //==========================================================================
3627 // ufoCreateNamelessForthWord
3629 //==========================================================================
3630 static UForthWord
*ufoCreateNamelessForthWord (void) {
3631 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
3632 fw
->name
= strdup("(nameless-word)");
3633 fw
->cfa
= &ufoDoForth
;
3634 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3635 fw
->flags
= UFW_FLAG_PROTECTED
| UFW_FLAG_HIDDEN
;
3636 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3637 fw
->pfastart
= ufoImageUsed
;
3639 ufoLinkWordToDict(fw
);
3640 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3641 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3646 //==========================================================================
3650 //==========================================================================
3651 static UForthWord
*doNativeCreate (void) {
3652 ufoParseNameToTempBuf();
3653 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3654 fw
->pfa
= ufoImageUsed
;
3655 fw
->pfastart
= ufoImageUsed
;
3662 // either native, or ZX, depending of the current mode
3664 if (ufoIsCompiling()) ufoFatal("already compiling");
3665 if (ufoInColon
!= 0) ufoFatal("invalid ':' usage");
3666 ufoWipeLocRecords();
3668 UForthWord
*fw
= doNativeCreate();
3669 fw
->cfa
= NULL
; // for now
3671 ufoSetStateCompile();
3672 //fprintf(stderr, "compiling native <%s>\n", wname);
3673 // always remember old mode
3674 ufoPush(0xdeadbeefU
); // just a flag
3679 UFWORD(VOCABULARY
) {
3680 ufoParseNameToTempBuf();
3681 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3682 fw
->pfa
= 0xffffffffU
;
3683 ufoCreateVocabData(fw
);
3686 // NESTED-VOCABULARY name
3687 UFWORD(NESTED_VOCABULARY
) {
3688 uint32_t prev
= ufoLastVoc
;
3689 UForthWord
*voc
= UFO_GET_CFAPROC(prev
);
3690 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("'NESTED_VOCABULARY' internal error");
3691 ufoParseNameToTempBuf();
3692 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3693 fw
->pfa
= 0xffffffffU
;
3694 ufoCreateVocabData(fw
);
3695 ufoLinkVocab(fw
, voc
);
3705 if (ufoVSP
== UFO_VOCSTACK_SIZE
) ufoFatal("vocabulary stack overflow");
3706 ufoVocStack
[ufoVSP
] = ufoImgGetU32(ufoAddrContext
);
3712 if (ufoVSP
== 0) ufoFatal("vocabulary stack underflow");
3714 ufoImgPutU32(ufoAddrContext
, ufoVocStack
[ufoVSP
]);
3718 UFWORD(DEFINITIONS
) {
3719 ufoImgPutU32(ufoAddrCurrent
, ufoImgGetU32(ufoAddrContext
));
3720 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3726 ufoParseNameToTempBuf();
3727 UForthWord
*fw
= ufoAlwaysWord(ufoTempCharBuf
);
3728 if (!UFO_VALID_VOC_FW(fw
)) ufoFatal("word '%s' is not a vocabulary", ufoTempCharBuf
);
3729 ufoPush(fw
->cfaidx
);
3734 UFWORD(VOC_PUBLIC_MODE
) {
3735 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3739 UFWORD(VOC_HIDDEN_MODE
) {
3740 ufoDefaultVocFlags
|= UFW_FLAG_VOC_HIDDEN
;
3743 // <PROTECTED-WORDS>
3744 UFWORD(VOC_PROTECTED_MODE
) {
3745 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
3748 // <UNPROTECTED-WORDS>
3749 UFWORD(VOC_UNPROTECTED_MODE
) {
3750 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
3756 if (ufoIsCompiling()) ufoFatal("already compiling");
3757 if (ufoInColon
!= 0) ufoFatal("invalid 'CREATE' usage");
3758 ufoWipeLocRecords();
3759 ufoInColon
= 0x00010000;
3760 UForthWord
*fw
= doNativeCreate();
3761 fw
->cfa
= &ufoDoVariable
; // for now
3762 //fw->flags |= UFW_FLAG_HIDDEN;
3767 UFWORD(CREATE_SEMI
) {
3768 if (ufoIsCompiling()) ufoFatal("already compiling");
3769 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'CREATE;' usage");
3770 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'CREATE;' usage");
3771 ufoLastDefinedNativeWord
= ufoColonWord
;
3772 ufoWipeLocRecords();
3774 ufoColonWord
->pfaend
= ufoImageUsed
;
3775 //ufoColonWord->flags &= ~UFW_FLAG_HIDDEN;
3780 if (ufoIsCompiling()) ufoFatal("already compiling");
3781 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'DOES>' usage");
3782 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'DOES>' usage");
3783 ufoColonWord
->cfa
= NULL
; // for semicolon
3784 ufoColonWord
->pfa
= ufoImageUsed
;
3785 ufoWipeLocRecords();
3787 // this is for semicolon
3789 ufoPush(0xdead0badU
); // just a flag
3790 ufoSetStateCompile();
3796 if (ufoIsInterpreting()) ufoFatal("not compiling");
3797 if (ufoInColon
!= 1) ufoFatal("where's my colon?");
3798 ufoLastDefinedNativeWord
= NULL
;
3801 const uint32_t guard
= ufoPop();
3802 if (guard
!= 0xdeadbeefU
&& guard
!= 0xdead0badU
) {
3803 ufoFatal("UFO finishing word primary magic imbalance!");
3805 // compile finishing word
3806 if (ufoColonWord
== NULL
|| ufoColonWord
->cfa
!= NULL
) ufoFatal("UFO ';' without ':'");
3807 ufo_assert(ufoColonWord
->pfa
!= 0xffffffffU
);
3808 ufoColonWord
->cfa
= &ufoDoForth
;
3809 if (ufoIsLocalsEnter(ufoColonWord
)) {
3810 ufoCompileCompilerWord("(L-LEAVE)");
3812 ufoCompileCompilerWord("(EXIT)");
3813 //ufoDecompileForth(ufoForthDict);
3814 ufoLastDefinedNativeWord
= ufoColonWord
;
3815 ufoColonWord
->pfaend
= ufoImageUsed
;
3816 ufoSetStateInterpret();
3817 // stack must be empty
3818 //if (ufoSP) ufoFatal("UFO finishing word primary imbalance!");
3820 ufoWipeLocRecords();
3822 ufoColonWord
= NULL
;
3824 // call optimiser if there is any
3825 UForthWord
*ofw
= ufoFindWordCompiler("OPTIMISE-WORD");
3826 if (ofw
&& ofw
!= ufoLastDefinedNativeWord
) {
3827 //if (ufoMode == UFO_MODE_ZX) fprintf(stderr, "**********000: #%04X\n", disp);
3828 ufoPush(ufoLastDefinedNativeWord
->cfaidx
);
3829 ufoExecuteNativeWordInVM(ofw
);
3835 if (ufoLastDefinedNativeWord
) {
3836 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_IMMEDIATE
;
3838 ufoFatal("wtf in `IMMEDIATE`");
3843 UFWORD(PAR_PROTECTED
) {
3844 if (ufoLastDefinedNativeWord
) {
3845 // we cannot unprotect the word
3846 ufoLastDefinedNativeWord
->flags
|= UFW_FLAG_PROTECTED
;
3848 ufoFatal("wtf in `(PROTECTED)`");
3853 UFWORD(PAR_HIDDEN
) {
3854 if (ufoLastDefinedNativeWord
) {
3855 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_VOC_HIDDEN
;
3857 ufoFatal("wtf in `(HIDDEN)`");
3861 UFWORD(RECURSE_IMM
) {
3863 //if (!ufoGetState()) ufoFatal("not compiling");
3864 if (ufoLastDefinedNativeWord
) {
3865 ufoImgEmitU32(ufoLastDefinedNativeWord
->cfaidx
);
3867 ufoFatal("wtf in `RECURSE`");
3872 //==========================================================================
3874 // ufoArgsLocalsCommon
3876 //==========================================================================
3877 static void ufoArgsLocalsCommon (uint32_t increment
) {
3878 uint32_t eidx
= ufoPrepareEnter(ufoColonWord
);
3879 uint32_t ch
= ufoGetInChar();
3884 if (dpos
>= UFO_MAX_WORD_LENGTH
- 1 || dpos
>= (uint32_t)sizeof(ufoTempCharBuf
)) {
3885 ufoFatal("name too long");
3887 ufoTempCharBuf
[dpos
] = (char)ch
; dpos
+= 1;
3888 ch
= ufoGetInChar();
3890 ufoTempCharBuf
[dpos
] = 0;
3891 if ((eidx
&0xffU
) > 127) ufoFatal("too many locals at '%s'", ufoTempCharBuf
);
3893 ufoNewLocal(ufoTempCharBuf
);
3895 ch
= ufoGetInChar();
3898 ufoUpdateEnter(ufoColonWord
, eidx
);
3901 // args: name name...
3902 UFWORD(ARGS_IMM
) { ufoArgsLocalsCommon(0x0101); } // increment high byte too
3903 // locals: name name...
3904 UFWORD(LOCALS_IMM
) { ufoArgsLocalsCommon(1); }
3907 //==========================================================================
3911 //==========================================================================
3912 UFO_FORCE_INLINE
void ufoLoadLocal (uint32_t lidx
) {
3913 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
3914 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3915 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3919 //==========================================================================
3923 //==========================================================================
3924 UFO_FORCE_INLINE
void ufoStoreLocal (uint32_t lidx
) {
3925 uint32_t value
= ufoPop();
3926 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
3927 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3928 ufoLStack
[ufoLBP
+ lidx
] = value
;
3934 UFWORD(LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3936 // (LOCAL@-1) .. (LOCAL@-7)
3937 UFWORD(LOCAL_LOAD_1
) { ufoLoadLocal(1); }
3938 UFWORD(LOCAL_LOAD_2
) { ufoLoadLocal(2); }
3939 UFWORD(LOCAL_LOAD_3
) { ufoLoadLocal(3); }
3940 UFWORD(LOCAL_LOAD_4
) { ufoLoadLocal(4); }
3941 UFWORD(LOCAL_LOAD_5
) { ufoLoadLocal(5); }
3942 UFWORD(LOCAL_LOAD_6
) { ufoLoadLocal(6); }
3943 UFWORD(LOCAL_LOAD_7
) { ufoLoadLocal(7); }
3944 UFWORD(LOCAL_LOAD_8
) { ufoLoadLocal(8); }
3945 UFWORD(LOCAL_LOAD_9
) { ufoLoadLocal(9); }
3946 UFWORD(LOCAL_LOAD_10
) { ufoLoadLocal(10); }
3947 UFWORD(LOCAL_LOAD_11
) { ufoLoadLocal(11); }
3948 UFWORD(LOCAL_LOAD_12
) { ufoLoadLocal(12); }
3949 UFWORD(LOCAL_LOAD_13
) { ufoLoadLocal(13); }
3950 UFWORD(LOCAL_LOAD_14
) { ufoLoadLocal(14); }
3951 UFWORD(LOCAL_LOAD_15
) { ufoLoadLocal(15); }
3952 UFWORD(LOCAL_LOAD_16
) { ufoLoadLocal(16); }
3956 UFWORD(LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3958 // (LOCAL!-1) .. (LOCAL!-7)
3959 UFWORD(LOCAL_STORE_1
) { ufoStoreLocal(1); }
3960 UFWORD(LOCAL_STORE_2
) { ufoStoreLocal(2); }
3961 UFWORD(LOCAL_STORE_3
) { ufoStoreLocal(3); }
3962 UFWORD(LOCAL_STORE_4
) { ufoStoreLocal(4); }
3963 UFWORD(LOCAL_STORE_5
) { ufoStoreLocal(5); }
3964 UFWORD(LOCAL_STORE_6
) { ufoStoreLocal(6); }
3965 UFWORD(LOCAL_STORE_7
) { ufoStoreLocal(7); }
3966 UFWORD(LOCAL_STORE_8
) { ufoStoreLocal(8); }
3967 UFWORD(LOCAL_STORE_9
) { ufoStoreLocal(9); }
3968 UFWORD(LOCAL_STORE_10
) { ufoStoreLocal(10); }
3969 UFWORD(LOCAL_STORE_11
) { ufoStoreLocal(11); }
3970 UFWORD(LOCAL_STORE_12
) { ufoStoreLocal(12); }
3971 UFWORD(LOCAL_STORE_13
) { ufoStoreLocal(13); }
3972 UFWORD(LOCAL_STORE_14
) { ufoStoreLocal(14); }
3973 UFWORD(LOCAL_STORE_15
) { ufoStoreLocal(15); }
3974 UFWORD(LOCAL_STORE_16
) { ufoStoreLocal(16); }
3977 // ////////////////////////////////////////////////////////////////////////// //
3980 // (CODEBLOCK) ( -- )
3981 UFWORD(CODEBLOCK_PAR
) {
3982 // current IP is "jump over" destination
3983 // next IP is cfaidx
3984 ufoPush(ufoImgGetU32(ufoIP
+1u)); // push cfa
3985 ufoIP
= ufoImgGetU32(ufoIP
); // branch over the code block
3988 // [: -- start code block
3989 UFWORD(CODEBLOCK_START_IMM
) {
3990 if (ufoInColon
<= 0) ufoInColon
-= 1; else ufoInColon
+= 1;
3992 ufoCompileCompilerWord("(CODEBLOCK)");
3994 ufoImgEmitU32(0); // jump over
3995 // create nameless word
3996 UForthWord
*fw
= ufoCreateNamelessForthWord();
3997 ufoImgEmitU32(fw
->cfaidx
); // cfaidx
3998 fw
->pfa
= ufoImageUsed
;
3999 fw
->pfastart
= ufoImageUsed
;
4001 ufoPush(UFO_QPAIRS_CBLOCK
);
4004 // ;] -- end code block
4005 UFWORD(CODEBLOCK_END_IMM
) {
4006 if (ufoInColon
== 0 || ufoInColon
== 1) ufoFatal("end of code block without start");
4007 if (ufoInColon
< 0) ufoInColon
+= 1; else ufoInColon
-= 1;
4008 if (!UFW_IS_HID(ufoForthDict
) || ufoForthDict
->cfa
!= &ufoDoForth
) {
4009 ufoFatal("invalid code block!");
4012 ufoPush(UFO_QPAIRS_CBLOCK
);
4014 ufoCompileCompilerWord("(EXIT)"); // finish code block
4016 ufoForthDict
->pfaend
= ufoImageUsed
;
4020 // ////////////////////////////////////////////////////////////////////////// //
4029 // ////////////////////////////////////////////////////////////////////////// //
4030 static void ufoDoVariable (UForthWord
*self
) { ufoPush(self
->pfa
); }
4031 static void ufoDoValue (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4032 static void ufoDoConst (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4034 static void ufoDoDefer (UForthWord
*self
) {
4035 const uint32_t cfaidx
= ufoImgGetU32(self
->pfastart
);
4036 ufoExecCFAIdx(cfaidx
);
4041 UForthWord
*fvar
= doNativeCreate();
4042 fvar
->cfa
= &ufoDoValue
;
4043 fvar
->pfa
= ufoImageUsed
;
4045 ufoImgEmitU32(ufoPop());
4046 fvar
->pfaend
= ufoImageUsed
;
4050 UFWORD(VAR_NOALLOT
) {
4051 UForthWord
*fvar
= doNativeCreate();
4052 fvar
->cfa
= &ufoDoVariable
;
4053 fvar
->pfa
= ufoImageUsed
;
4054 // no variable value yet
4059 UForthWord
*fvar
= doNativeCreate();
4060 fvar
->cfa
= &ufoDoVariable
;
4061 fvar
->pfa
= ufoImageUsed
;
4063 ufoImgEmitU32(ufoPop());
4064 fvar
->pfaend
= ufoImageUsed
;
4069 UForthWord
*fvar
= doNativeCreate();
4070 fvar
->cfa
= &ufoDoConst
;
4071 fvar
->pfa
= ufoImageUsed
;
4073 ufoImgEmitU32(ufoPop());
4074 fvar
->pfaend
= ufoImageUsed
;
4079 UForthWord
*fvar
= doNativeCreate();
4080 fvar
->cfa
= &ufoDoDefer
;
4081 fvar
->pfa
= ufoImageUsed
;
4083 ufoImgEmitU32(ufoPop());
4084 fvar
->pfaend
= ufoImageUsed
;
4088 // ( size -- startaddr )
4089 // this cannot "deallot" memory
4091 uint32_t sz
= (int32_t)ufoPop();
4092 if (sz
>= 1024*1024*64) ufoFatal("cannot allot %u bytes", sz
);
4093 ufoImgEnsureSize(ufoImageUsed
+ sz
);
4094 ufoPush(ufoImageUsed
);
4106 // ( addr count -- here size )
4107 // load data file from disk, put it to HERE
4108 // file is unpacked to cells (i.e. each byte will occupy one cell)
4109 // the usual "!" and "*" modifiers are ok
4110 UFWORD(LOAD_DATA_FILE
) {
4111 ufoPopStrLitToTempBuf();
4112 const char *orgname
= ufoTempCharBuf
;
4113 int system
= 0, softinclude
= 0;
4114 while (*orgname
!= 0) {
4115 if (*orgname
== '!') {
4116 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4118 } else if (*orgname
== '?') {
4119 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4126 } while (*orgname
> 0 && *orgname
<= 32);
4128 if (*orgname
== 0) ufoFatal("empty file name");
4130 const uint32_t addr
= ufoPop();
4132 char *fname
= ufoCreateIncludeName(orgname
, system
, ufoLastIncPath
);
4133 FILE *fl
= fopen(fname
, "rb");
4135 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4139 ssize_t res
= fread(&bt
, 1, 1, fl
);
4141 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4143 ufoImgPutU8(addr
+ count
, bt
); count
+= 1;
4152 // ZX-LOAD-DATA-FILE
4153 // ( addr count -- )
4154 // load data file from disk, put it to org, advance org
4155 // the usual "!" and "*" modifiers are ok
4156 UFWORD(ZX_LOAD_DATA_FILE
) {
4157 ufoPopStrLitToTempBuf();
4158 const char *orgname
= ufoTempCharBuf
;
4159 int system
= 0, softinclude
= 0;
4160 while (*orgname
!= 0) {
4161 if (*orgname
== '!') {
4162 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4164 } else if (*orgname
== '?') {
4165 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4172 } while (*orgname
> 0 && *orgname
<= 32);
4174 if (*orgname
== 0) ufoFatal("empty file name");
4175 char *fname
= ufoCreateIncludeName(orgname
, system
, ufoLastIncPath
);
4176 FILE *fl
= fopen(fname
, "rb");
4178 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4182 ssize_t res
= fread(&bt
, 1, 1, fl
);
4184 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4196 UForthWord
*fw
= ufoNTWordAddrCount();
4197 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4198 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4200 if (ufoIsCompiling()) {
4203 ufoCompileLiteral(fw
->pfa
);
4204 ufoCompileForthWord("!");
4207 ufoImgPutU32(fw
->pfa
, ufoPop());
4212 // ( value addr count -- )
4214 UForthWord
*fw
= ufoNTWordAddrCount();
4215 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4216 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4218 if (ufoIsCompiling()) {
4221 ufoCompileLiteral(fw
->pfa
);
4222 ufoCompileForthWord("!");
4225 ufoImgPutU32(fw
->pfa
, ufoPop());
4232 uint32_t cfa
= ufoPop();
4233 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
4238 // ////////////////////////////////////////////////////////////////////////// //
4241 UFWORD(LSQBRACKET_IMM
) {
4242 ufoSetStateInterpret();
4246 UFWORD(RSQBRACKET
) {
4247 ufoSetStateCompile();
4251 // ////////////////////////////////////////////////////////////////////////// //
4255 // ( addr count -- flag )
4256 UFWORD(UR_HAS_LABELQ
) {
4257 ufoPopStrLitToTempBuf();
4258 ufoPushBool(ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
);
4262 // ( addr count -- type )
4264 UFWORD(UR_GET_LABELQ_TYPE
) {
4265 ufoPopStrLitToTempBuf();
4266 ufoPush(ufoZXGetLabelType(ufoTempCharBuf
));
4270 // ( addr count -- value )
4271 // fatals when the label is not found
4272 UFWORD(UR_GET_LABELQ
) {
4273 ufoPopStrLitToTempBuf();
4274 ufoPush((uint32_t)ufoZXGetLabelValue(ufoTempCharBuf
));
4282 //==========================================================================
4286 //==========================================================================
4287 static uint32_t zxLabelIter (const char *name
, int type
, int value
, void *udata
) {
4288 LIterInfo
*nfo
= (LIterInfo
*)udata
;
4289 uint32_t addr
= ufoPutTempStrLiteral(name
);
4290 uint32_t count
= ufoImgGetU32(addr
++);
4293 ufoExecCFAIdxInVM(nfo
->cfaidx
);
4299 // EXECUTEs cfa, returns final res
4300 // cfa: ( addr count -- stopflag )
4301 // i.e. return non-zero from cfa to stop
4302 // res is the result of the last called cfa
4303 UFWORD(UR_FOREACH_LABEL
) {
4305 nfo
.cfaidx
= ufoPop();
4306 uint32_t res
= ufoZXForeachLabel(&zxLabelIter
, &nfo
);
4307 ufoPush((uint32_t)res
);
4311 //==========================================================================
4313 // urw_set_typed_label
4315 // ( value addr count -- )
4317 //==========================================================================
4318 static void urw_set_typed_label (UForthWord
*self
, int type
) {
4319 ufoPopStrLitToTempBuf();
4320 const char *name
= ufoTempCharBuf
;
4321 int32_t val
= (int32_t)ufoPop();
4322 ufoZXSetLabelValue(name
, type
, val
);
4327 // ( value addr count -- )
4328 // create/overwrite an "assign" label
4329 UFWORD(UR_SET_LABEL_VAR
) { urw_set_typed_label(self
, UFO_ZX_LABEL_VAR
); }
4332 // ( value addr count -- )
4333 UFWORD(UR_SET_LABEL_EQU
) { urw_set_typed_label(self
, UFO_ZX_LABEL_EQU
); }
4335 // UR-SET-LABEL-CODE
4336 // ( value addr count -- )
4337 UFWORD(UR_SET_LABEL_CODE
) { urw_set_typed_label(self
, UFO_ZX_LABEL_CODE
); }
4339 // UR-SET-LABEL-STOFS
4340 // ( value addr count -- )
4341 UFWORD(UR_SET_LABEL_STOFS
) { urw_set_typed_label(self
, UFO_ZX_LABEL_STOFS
); }
4343 // UR-SET-LABEL-DATA
4344 // ( value addr count -- )
4345 UFWORD(UR_SET_LABEL_DATA
) { urw_set_typed_label(self
, UFO_ZX_LABEL_DATA
); }
4348 //==========================================================================
4350 // urw_declare_typed_label
4352 //==========================================================================
4353 static void urw_declare_typed_label (UForthWord
*self
, int type
) {
4355 ufoParseNameToTempBuf();
4356 if (ufoTempCharBuf
[0] == 0) ufoFatal("label name expected");
4357 const char *name
= ufoTempCharBuf
;
4358 ufoZXSetLabelValue(name
, type
, ufoZXGetOrg());
4361 // $LABEL-DATA: name
4362 UFWORD(DLR_LABEL_DATA_IMM
) { urw_declare_typed_label(self
, UFO_ZX_LABEL_DATA
); }
4363 // $LABEL-CODE: name
4364 UFWORD(DLR_LABEL_CODE_IMM
) { urw_declare_typed_label(self
, UFO_ZX_LABEL_CODE
); }
4370 ufoPush(ufoZXGetPass());
4376 ufoPush(ufoZXGetOrg());
4381 UFWORD(UR_GETDISP
) {
4382 ufoPush(ufoZXGetDisp());
4388 ufoPush(ufoZXGetEnt());
4395 const uint32_t addr
= ufoPop();
4401 // doesn't change ORG
4402 UFWORD(UR_SETDISP
) {
4403 const uint32_t addr
= ufoPop();
4410 const uint32_t addr
= ufoPop();
4415 // ////////////////////////////////////////////////////////////////////////// //
4416 // conditional compilation
4418 typedef struct UForthCondDefine_t UForthCondDefine
;
4419 struct UForthCondDefine_t
{
4421 UForthCondDefine
*prev
;
4424 static UForthCondDefine
*ufoCondDefines
= NULL
;
4427 //==========================================================================
4429 // ufoClearCondDefines
4431 //==========================================================================
4432 static void ufoClearCondDefines (void) {
4433 while (ufoCondDefines
) {
4434 UForthCondDefine
*df
= ufoCondDefines
;
4435 ufoCondDefines
= df
->prev
;
4436 if (df
->name
) free(df
->name
);
4442 //==========================================================================
4446 //==========================================================================
4447 static int ufoHasCondDefine (const char *name
) {
4448 if (!name
|| !name
[0]) return 0;
4449 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4450 if (strcmp(dd
->name
, name
) == 0) return 1;
4456 //==========================================================================
4460 //==========================================================================
4461 static void ufoAddCondDefine (const char *name
) {
4462 if (!name
|| !name
[0]) return;
4463 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4464 if (strcmp(dd
->name
, name
) == 0) return;
4466 UForthCondDefine
*dd
= malloc(sizeof(UForthCondDefine
));
4467 dd
->name
= strdup(name
);
4468 dd
->prev
= ufoCondDefines
;
4469 ufoCondDefines
= dd
;
4473 //==========================================================================
4475 // ufoRemoveCondDefine
4477 //==========================================================================
4478 static void ufoRemoveCondDefine (const char *name
) {
4479 if (!name
|| !name
[0]) return;
4480 UForthCondDefine
*pp
= NULL
;
4481 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4482 if (strcmp(dd
->name
, name
) == 0) {
4483 if (pp
) pp
->prev
= dd
->prev
; else ufoCondDefines
= dd
->prev
;
4493 //==========================================================================
4495 // ufoParseConditionTerm
4497 //==========================================================================
4498 static int ufoParseConditionTerm (int doskip
) {
4500 if (strEquCI(ufoTempCharBuf
, "DEFINED")) {
4501 ufoParseNameToTempBuf();
4502 res
= (doskip
? 0 : ufoHasCondDefine(ufoTempCharBuf
));
4503 } else if (strEquCI(ufoTempCharBuf
, "UNDEFINED")) {
4504 ufoParseNameToTempBuf();
4505 res
= (doskip
? 0 : !ufoHasCondDefine(ufoTempCharBuf
));
4506 } else if (strEquCI(ufoTempCharBuf
, "HAS-WORD")) {
4507 ufoParseNameToTempBuf();
4508 res
= (doskip
? 0 : !!ufoFindWord(ufoTempCharBuf
));
4509 } else if (strEquCI(ufoTempCharBuf
, "NO-WORD")) {
4510 ufoParseNameToTempBuf();
4511 res
= (doskip
? 0 : !ufoFindWord(ufoTempCharBuf
));
4512 } else if (strEquCI(ufoTempCharBuf
, "HAS-LABEL")) {
4513 ufoParseNameToTempBuf();
4514 res
= (doskip
? 0 : ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
);
4515 } else if (strEquCI(ufoTempCharBuf
, "NO-LABEL")) {
4516 ufoParseNameToTempBuf();
4517 res
= (doskip
? 0 : ufoZXGetLabelType(ufoTempCharBuf
) <= UFO_ZX_LABEL_UNKNOWN
);
4518 } else if (strEquCI(ufoTempCharBuf
, "PASS0")) {
4519 res
= (doskip
? 0 : (ufoZXGetPass() == 0));
4520 } else if (strEquCI(ufoTempCharBuf
, "PASS1")) {
4521 res
= (doskip
? 0 : (ufoZXGetPass() == 1));
4527 if (ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
) {
4528 res
= ufoZXGetLabelValue(ufoTempCharBuf
);
4532 res
= !!strtol(ufoTempCharBuf
, &e
, 10);
4533 if (*e
) ufoFatal("undefined label '%s'", ufoTempCharBuf
);
4537 ufoParseNameToTempBufEmptyOk();
4542 //==========================================================================
4544 // ufoParseConditionUnary
4546 //==========================================================================
4547 static int ufoParseConditionUnary (int doskip
) {
4549 if (strEquCI(ufoTempCharBuf
, "(")) {
4550 res
= ufoParseConditionExpr(doskip
);
4551 if (!strEquCI(ufoTempCharBuf
, ")")) ufoFatal("unbalanced parens in $IF condition");
4552 } else if (strEquCI(ufoTempCharBuf
, "NOT")) {
4553 ufoParseNameToTempBuf();
4554 res
= !ufoParseConditionUnary(doskip
);
4556 res
= ufoParseConditionTerm(doskip
);
4562 //==========================================================================
4564 // ufoParseConditionAnd
4566 //==========================================================================
4567 static int ufoParseConditionAnd (int doskip
) {
4568 int res
= ufoParseConditionUnary(doskip
);
4569 doskip
= (res
== 0);
4570 while (strEquCI(ufoTempCharBuf
, "AND") || strEquCI(ufoTempCharBuf
, "&&")) {
4571 ufoParseNameToTempBuf();
4572 int r2
= ufoParseConditionUnary(doskip
);
4575 doskip
= (res
== 0);
4582 //==========================================================================
4584 // ufoParseConditionOr
4586 //==========================================================================
4587 static int ufoParseConditionOr (int doskip
) {
4588 int res
= ufoParseConditionAnd(doskip
);
4589 doskip
= (res
!= 0);
4590 while (strEquCI(ufoTempCharBuf
, "OR") || strEquCI(ufoTempCharBuf
, "||")) {
4591 ufoParseNameToTempBuf();
4592 int r2
= ufoParseConditionAnd(doskip
);
4595 doskip
= (res
!= 0);
4602 //==========================================================================
4604 // ufoParseConditionExpr
4606 //==========================================================================
4607 static int ufoParseConditionExpr (int doskip
) {
4608 return ufoParseConditionOr(doskip
);
4612 //==========================================================================
4614 // ufoSkipConditionals
4616 //==========================================================================
4617 static void ufoSkipConditionals (int toelse
) {
4618 const int oldCondStLine
= ufoCondStLine
;
4619 ufoCondStLine
= ufoInFileLine
;
4620 int iflevel
= 0, done
= 0;
4623 ufoParseNameToTempBufEmptyOk();
4624 if (ufoTempCharBuf
[0]) {
4625 // nested conditionals
4626 if (strEquCI(ufoTempCharBuf
, "$IF")) {
4628 } else if (strEquCI(ufoTempCharBuf
, "$ENDIF")) {
4629 // in nested ifs, look only for $ENDIF
4633 // it doesn't matter which part we're skipping, it ends here anyway
4636 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELSE")) {
4637 // if we're skipping "true" part, go on
4641 // we're skipping "false" part, there should be no else
4642 ufoFatal("unexpected $ELSE, skipping from line %d", ufoCondStLine
);
4645 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELIF")) {
4646 // if we're skipping "true" part, go on
4648 // process the conditional
4649 int res
= ufoParseConditionExpr(0);
4650 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4651 // either resume normal execution, or keep searching for $ELSE
4657 // we're skipping "false" part, there should be no else
4658 ufoFatal("unexpected $ELIFxx, skipping from line %d", ufoCondStLine
);
4662 } while (done
== 0);
4663 ufo_assert(iflevel
== 0);
4665 ufoCondStLine
= oldCondStLine
;
4669 //==========================================================================
4671 // ufoProcessConditional
4673 //==========================================================================
4674 static void ufoProcessConditional (void) {
4675 ufoParseNameToTempBuf();
4676 int res
= ufoParseConditionExpr(0);
4677 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4679 ufoSkipConditionals(1); // skip to $ELSE
4687 // ( count addr -- )
4688 UFWORD(ASM_WARNING
) {
4689 ufoPopStrLitToTempBuf();
4690 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4691 fprintf(stdout
, "*** USER WARNING ");
4692 if (ufoInFile
!= NULL
) {
4693 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4695 fprintf(stdout
, "somewhere in time: ");
4697 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4702 // ( count addr -- )
4704 ufoPopStrLitToTempBuf();
4705 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4706 fprintf(stdout
, "*** USER ERROR ");
4707 if (ufoInFile
!= NULL
) {
4708 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4710 fprintf(stdout
, "somewhere in time: ");
4712 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4718 UFWORD(DLR_DEFINE
) {
4719 ufoParseNameToTempBuf();
4720 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4721 ufoAddCondDefine(ufoTempCharBuf
);
4726 ufoParseNameToTempBuf();
4727 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4728 ufoRemoveCondDefine(ufoTempCharBuf
);
4731 // these words can be encoundered only when we're done with some $IF, so skip to $ENDIF
4733 UFWORD(DLR_ELSE_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELSE without $IF"); ufoSkipConditionals(0); }
4735 UFWORD(DLR_ELIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELIF without $IF"); --ufoInCondIf
; ufoSkipConditionals(0); }
4737 UFWORD(DLR_ENDIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ENDIF without $IF"); --ufoInCondIf
; }
4740 UFWORD(DLR_IF_IMM
) { ufoProcessConditional(); }
4744 // ( addr count -- )
4747 uint32_t count
= ufoPop();
4748 uint32_t addr
= ufoPop();
4750 int system
= 0, softinclude
= 0;
4753 while (count
!= 0) {
4754 ch
= ufoImgGetU8(addr
);
4756 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4758 } else if (ch
== '?') {
4759 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4765 addr
+= 1; count
-= 1;
4766 ch
= ufoImgGetU8(addr
);
4767 } while (ch
<= 32 && count
!= 0);
4771 if ((size_t)count
>= sizeof(fname
)) ufoFatal("include file name too long");
4773 while (count
!= 0) {
4774 fname
[dpos
] = (char)ufoImgGetU8(addr
); dpos
+= 1;
4775 addr
+= 1; count
-= 1;
4779 char *ffn
= ufoCreateIncludeName(fname
, system
, ufoLastIncPath
);
4780 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4782 if (softinclude
) { free(ffn
); return; }
4783 ufoFatal("INCLUDE: file '%s' not found", ffn
);
4788 ufoInFileName
= ffn
;
4789 setLastIncPath(ufoInFileName
);
4791 // trigger next line loading
4792 ufoSetTIB(0); ufoSetIN(0);
4797 //==========================================================================
4799 // ufoDollarIncludeCommon
4801 //==========================================================================
4802 static void ufoDollarIncludeCommon (const char *defname
) {
4805 int system
= 0, softinclude
= 0;
4807 int skipit
= (defname
!= NULL
&& ufoHasCondDefine(defname
));
4809 ch
= ufoGetInChar();
4810 while (ch
!= 0 && ch
!= '"' && ch
!= '<') {
4811 ch
= ufoGetInChar();
4814 if (ch
== 0) ufoFatal("quoted file name expected");
4816 if (ch
== '<') { system
= 1; qch
= '>'; } else qch
= '"';
4817 ch
= ufoGetInChar();
4819 if (ch
== 0) ufoFatal("properly quoted file name expected");
4821 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4823 } else if (ch
== '?') {
4824 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4830 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
!= qch
);
4835 while (ch
!= 0 && ch
!= qch
) {
4836 if ((size_t)dpos
>= sizeof(fname
)) ufoFatal("include file name too long");
4837 fname
[dpos
] = (char)ch
; dpos
+= 1;
4838 ch
= ufoGetInChar();
4841 // final parsing checks
4842 if (ch
== 0) ufoFatal("properly quoted file name expected");
4843 ch
= ufoGetInChar();
4845 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
<= 32);
4846 if (ch
!= 0) ufoFatal("unexpected extra text");
4849 if (defname
!= NULL
) ufoAddCondDefine(defname
);
4850 char *ffn
= ufoCreateIncludeName(fname
, system
, ufoLastIncPath
);
4851 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4853 if (softinclude
) { free(ffn
); return; }
4854 ufoFatal("$INCLUDE: file '%s' not found", ffn
);
4859 ufoInFileName
= ffn
;
4860 setLastIncPath(ufoInFileName
);
4863 // trigger next line loading
4864 ufoSetTIB(0); ufoSetIN(0);
4869 // $INCLUDE-ONCE define-guard filename
4870 UFWORD(DLR_INCLUDE_ONCE
) {
4871 ufoParseNameToTempBuf();
4872 ufoDollarIncludeCommon(ufoTempCharBuf
);
4875 // $INCLUDE filename
4876 UFWORD(DLR_INCLUDE
) {
4877 ufoDollarIncludeCommon(NULL
);
4883 UFWORD(DUMP_STACK
) {
4884 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4885 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
4886 for (uint32_t sp
= 0; sp
< ufoSP
; ++sp
) {
4887 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
4895 //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]);
4896 ufoPopStrLitToTempBuf();
4897 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4898 ufoFatal("%s", ufoTempCharBuf
);
4902 // ////////////////////////////////////////////////////////////////////////// //
4906 //==========================================================================
4908 // ufoSetForthOnlyDefs
4910 //==========================================================================
4911 static void ufoSetForthOnlyDefs (void) {
4912 ufoImgPutU32(ufoAddrCurrent
, ufoForthVocCFA
);
4913 ufoImgPutU32(ufoAddrContext
, ufoForthVocCFA
);
4917 //==========================================================================
4919 // ufoCreateVocSetOnlyDefs
4921 //==========================================================================
4922 static UForthWord
*ufoCreateVocSetOnlyDefs (const char *wname
, UForthWord
*parentvoc
) {
4923 UForthWord
*fw
= ufoRegisterWord(wname
, NULL
, ufoDefaultVocFlags
);
4924 fw
->pfa
= 0xffffffffU
;
4925 ufoCreateVocabData(fw
);
4927 ufoLinkVocab(fw
, parentvoc
);
4928 // and set as active
4929 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
4930 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
4935 //==========================================================================
4937 // ufoVocSetOnlyDefs
4939 //==========================================================================
4940 __attribute__((unused
)) static void ufoVocSetOnlyDefs (UForthWord
*fw
) {
4941 if (UFO_VALID_VOC_FW(fw
)) {
4942 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
4943 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
4945 ufoSetForthOnlyDefs();
4950 //==========================================================================
4954 //==========================================================================
4955 static void ufoDefine (const char *wname
) {
4956 UForthWord
*fw
= ufoRegisterWord(wname
, &ufoDoForth
, ufoDefaultVocFlags
);
4957 fw
->pfa
= ufoImageUsed
;
4958 fw
->pfastart
= ufoImageUsed
;
4960 //fprintf(stderr, "***DEFINING #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
4961 ufoSetStateCompile();
4965 //==========================================================================
4969 //==========================================================================
4970 static void ufoDefineDone (void) {
4971 ufoLastDefinedNativeWord
= NULL
;
4973 if (ufoSP
) ufoFatal("UFO finishing word primary imbalance!");
4974 //if (!ufoForthDict || ufoForthDict->cfa) ufoFatal("UFO ';' without ':'");
4975 ufo_assert(ufoForthDict
->pfa
!= 0xffffffffU
);
4976 ufoForthDict
->cfa
= &ufoDoForth
;
4977 ufoForthDict
->pfaend
= ufoImageUsed
;
4978 ufoCompileCompilerWord("(EXIT)");
4979 //ufoDecompileForth(ufoForthDict);
4980 ufoLastDefinedNativeWord
= ufoForthDict
;
4981 ufoSetStateInterpret();
4985 //==========================================================================
4989 //==========================================================================
4990 static void ufoNumber (uint32_t v
) {
4991 ufoCompileCompilerWord("LIT");
4996 //==========================================================================
5000 //==========================================================================
5001 static void ufoCompile (const char *wname
) {
5002 UForthWord
*fw
= ufoFindWord(wname
);
5006 long v
= strtol(wname
, &end
, 0);
5007 if (end
== wname
|| *end
) ufoFatal("UFO word '%s' not found", wname
);
5008 ufoNumber((uint32_t)v
);
5010 // compile/execute a word
5011 if (UFW_IS_IMM(fw
)) {
5012 ufoExecuteNativeWordInVM(fw
);
5014 ufoCompileWordCFA(fw
);
5020 //==========================================================================
5024 //==========================================================================
5025 static __attribute__((unused
)) void ufoString (const char *str
) {
5026 ufoCompileCompilerWord("(\")");
5028 size_t slen
= strlen(str
);
5029 if (slen
> 65535) ufoFatal("UFO string too long");
5030 ufoImgEmitU32((uint32_t)slen
);
5032 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5038 //==========================================================================
5042 //==========================================================================
5043 static __attribute__((unused
)) void ufoDotString (const char *str
) {
5044 ufoCompileCompilerWord("(.\")");
5046 size_t slen
= strlen(str
);
5047 if (slen
> 65535) ufoFatal("UFO string too long");
5048 ufoImgEmitU32((uint32_t)slen
);
5050 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5056 // ////////////////////////////////////////////////////////////////////////// //
5058 #include "urforth_dbg.c"
5062 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5064 ufoFatal("there is no UFO debug breakpoint support in windoze");
5066 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
5069 fprintf(stderr
, "WARNING: cannot start UFO debug session, because standard streams are not on TTY!\n");
5075 // ////////////////////////////////////////////////////////////////////////// //
5079 // ( vocid -- cfa / 0 )
5080 UFWORD(WORDS_ITER_NEW
) {
5081 uint32_t vocid
= ufoPop();
5082 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5083 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("WORDS-ITER-NEW expects a valid vocid");
5084 UForthWord
*fw
= voc
->latest
;
5085 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5086 uint32_t cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5091 // ( cfa -- cfa / 0 )
5092 // closes iterator on completion
5093 UFWORD(WORDS_ITER_PREV
) {
5094 uint32_t cfa
= ufoPop();
5095 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5096 if (fw
!= NULL
) fw
= fw
->prevVoc
;
5097 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5098 cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5103 // ( cfa -- addr count )
5104 // somewhere at PAD; invalid CFA returns empty string
5105 UFWORD(WORDS_ITER_NAME
) {
5106 uint32_t cfa
= ufoPop();
5107 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5108 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5109 uint32_t addr
= ufoPutTempStrLiteral(fw
->name
);
5110 uint32_t count
= ufoImgGetU32(addr
++);
5114 uint32_t dest
= ufoPadAddr();
5115 ufoImgPutU32(dest
, 0);
5116 ufoImgPutU32(dest
+1, 0);
5118 ufoPush(0u); // count
5123 // ( cfa -- pfa / 0 )
5124 UFWORD(WORDS_ITER_PFA
) {
5125 uint32_t cfa
= ufoPop();
5126 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5127 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5136 UFWORD(WORDS_ITER_IMMQ
) {
5137 uint32_t cfa
= ufoPop();
5138 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5139 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5140 ufoPushBool(UFW_IS_IMM(fw
));
5148 UFWORD(WORDS_ITER_PROTQ
) {
5149 uint32_t cfa
= ufoPop();
5150 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5151 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5152 ufoPushBool(UFW_IS_PROT(fw
));
5158 // WORDS-ITER-HIDDEN?
5160 UFWORD(WORDS_ITER_HIDDENQ
) {
5161 uint32_t cfa
= ufoPop();
5162 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5163 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5164 ufoPushBool(UFW_IS_VOC_HID(fw
));
5181 UFWORD(WORDS_ITER_TYPEQ
) {
5182 uint32_t cfa
= ufoPop();
5183 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5184 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5185 if (fw
->cfa
== &ufoDoForth
) ufoPush(fw
->pfa
== fw
->pfastart
? 2 : 7);
5186 else if (fw
->cfa
== &ufoDoVariable
) ufoPush(3);
5187 else if (fw
->cfa
== &ufoDoValue
) ufoPush(4);
5188 else if (fw
->cfa
== &ufoDoConst
) ufoPush(5);
5189 else if (fw
->cfa
== &ufoDoDefer
) ufoPush(6);
5190 else if (fw
->cfa
== &ufoDoVoc
) ufoPush(7);
5191 else ufoPush(1); // code
5199 // ( vocid cfa -- res )
5200 // EXECUTEs cfa, returns final res
5201 // cfa: ( wordcfa -- stopflag )
5202 // i.e. return non-zero from cfa to stop
5203 // res is the result of the last called cfa
5204 UFWORD(UFO_FOREACH_WORD
) {
5205 uint32_t cfaidx
= ufoPop();
5206 uint32_t vocid
= ufoPop();
5208 UForthWord
*fw
= NULL
;
5209 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5210 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("FOREACH-WORD expects a valid vocid");
5212 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5215 while (res
== 0 && fw
!= NULL
) {
5216 if (fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5217 ufoPush(fw
->cfaidx
);
5218 ufoExecCFAIdxInVM(cfaidx
);
5228 // ////////////////////////////////////////////////////////////////////////// //
5232 UFWORD(DLR_END_FORTH
) {
5233 if (ufoMode
!= UFO_MODE_NATIVE
) ufoFatal("$END_FORTH in non-native mode");
5234 if (ufoIsCompiling()) ufoFatal("$END_FORTH: still compiling something");
5235 longjmp(ufoInlineQuitJP
, 1);
5239 //==========================================================================
5241 // ufoDecompileForth
5243 //==========================================================================
5244 static void ufoDecompileForthPart (uint32_t addr
, uint32_t endaddr
, int indent
) {
5245 while (addr
!= 0 && addr
< ufoImageUsed
&& addr
< endaddr
) {
5246 uint32_t cfaidx
= ufoImgGetU32(addr
);
5247 fprintf(stderr
, "%8u: ", addr
);
5248 for (int f
= 0; f
< indent
; f
+= 1) fputc(' ', stderr
);
5249 if ((cfaidx
& UFO_RS_CFA_BIT
) == 0) {
5250 fprintf(stderr
, "<bad-cfa>");
5253 cfaidx
&= UFO_RS_CFA_MASK
;
5254 if (cfaidx
>= ufoCFAsUsed
) {
5255 fprintf(stderr
, "<bad-cfa>");
5258 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
5259 fprintf(stderr
, "%s", fw
->name
);
5261 if (fw
->cfa
== UFCFA(BRANCH
) ||
5262 fw
->cfa
== UFCFA(0BRANCH
) ||
5263 fw
->cfa
== UFCFA(TBRANCH
) ||
5264 fw
->cfa
== UFCFA(LOOP_PAREN
) ||
5265 fw
->cfa
== UFCFA(PLOOP_PAREN
))
5267 uint32_t jaddr
= ufoImgGetU32(addr
++);
5268 fprintf(stderr
, " %u", jaddr
);
5269 } else if (fw
->cfa
== UFCFA(LIT
) || fw
->cfa
== UFCFA(PAR_LENTER
)) {
5270 uint32_t n
= ufoImgGetU32(addr
++);
5271 fprintf(stderr
, " %u", n
);
5272 } else if (fw
->cfa
== UFCFA(STRQ_PAREN
) || fw
->cfa
== UFCFA(STRDOTQ_PAREN
)) {
5273 uint32_t count
= ufoImgGetU32(addr
++);
5274 fprintf(stderr
, " cnt=%u; ~", count
);
5276 uint8_t ch
= ufoImgGetU32(addr
++)&0xffU
;
5277 if (ch
== '\r') fprintf(stderr
, "\\r");
5278 else if (ch
== '\n') fprintf(stderr
, "\\n");
5279 else if (ch
== '\t') fprintf(stderr
, "\\t");
5280 else if (ch
== '\\') fprintf(stderr
, "\\\\");
5281 else if (ch
== '"') fprintf(stderr
, "\\`");
5282 else if (ch
< 32 || ch
== 127) fprintf(stderr
, "\\x%02x", ch
);
5283 else fprintf(stderr
, "%c", (char)ch
);
5285 fprintf(stderr
, "~");
5286 } else if (fw
->cfa
== UFCFA(CODEBLOCK_PAR
)) {
5287 uint32_t jover
= ufoImgGetU32(addr
++);
5288 addr
+= 1; // skip cfa idx
5289 fputc('\n', stderr
);
5290 ufoDecompileForthPart(addr
, jover
, indent
+ 2);
5296 fputc('\n', stderr
);
5301 //==========================================================================
5303 // ufoDecompileForth
5305 //==========================================================================
5306 static void ufoDecompileForth (UForthWord
*fw
) {
5308 fprintf(stderr
, "====: %s", fw
->name
);
5309 if (fw
->cfa
== &ufoDoForth
) {
5310 if (fw
->pfa
!= fw
->pfastart
) {
5311 fprintf(stderr
, " -- DOES, data at %d", fw
->pfastart
);
5313 fputc('\n', stderr
);
5314 ufoDecompileForthPart(fw
->pfa
, fw
->pfaend
, 0);
5315 } else if (fw
->cfa
== ufoDoDefer
) {
5316 fprintf(stderr
, " -- DEFER\n");
5317 } else if (fw
->cfa
== ufoDoConst
) {
5318 fprintf(stderr
, " -- CONSTANT\n");
5319 } else if (fw
->cfa
== ufoDoValue
) {
5320 fprintf(stderr
, " -- VALUE\n");
5321 } else if (fw
->cfa
== ufoDoVariable
) {
5322 fprintf(stderr
, " -- VARIABLE\n");
5324 fprintf(stderr
, "----\n");
5328 // ( addr count -- )
5329 UFWORD(UFO_DECOMPILE_INTERNAL
) {
5330 UForthWord
*fw
= ufoNTWordAddrCount();
5331 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5332 ufoDecompileForth(fw
);
5335 // (UFO-BUCKET-STATS)
5337 UFWORD(PAR_UFO_BUCKET_STATS) {
5338 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
5339 int used = 0, min = 0x7fffffff, max = -1;
5340 for (unsigned f = 0; f < UFO_DICT_HASH_BUCKETS; f += 1) {
5341 UForthWord *fw = ufoForthDictBuckets[f];
5345 while (fw != NULL) { total += 1; fw = fw->hlink; }
5346 if (total < min) min = total;
5347 if (total > max) max = total;
5350 printf("BUCKETS USED: %d\n", used);
5352 printf("MIN BUCKET: %d\n", min);
5353 printf("MAX BUCKET: %d\n", max);
5359 // ////////////////////////////////////////////////////////////////////////// //
5362 #define UFWORD(name_) ufoRegisterWord(""#name_, ufoWord_##name_, ufoDefaultVocFlags)
5363 #define UFWORDX(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, ufoDefaultVocFlags)
5365 #define UFWORD_IMM(name_) ufoRegisterWord(""#name_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5366 #define UFWORDX_IMM(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5369 #define UFC(wn_) ufoCompile(""#wn_);
5370 #define UFS(wn_) ufoString(""#wn_);
5371 #define UFDS(wn_) ufoDotString(""#wn_);
5372 #define UFN(wn_) ufoNumber(wn_);
5374 #define UFBEGIN UFCALL(BEGIN);
5375 #define UFAGAIN UFCALL(AGAIN);
5378 //==========================================================================
5382 //==========================================================================
5383 static void ufoDefineQuit (void) {
5384 ufoDefine("UFO-RUN-LOOP");
5393 //==========================================================================
5395 // ufoDefineConstant
5397 //==========================================================================
5398 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5399 UForthWord
*fw
= ufoRegisterWord(name
, &ufoDoConst
, ufoDefaultVocFlags
);
5400 fw
->pfa
= ufoImageUsed
;
5401 fw
->pfastart
= ufoImageUsed
;
5403 ufoImgEmitU32(value
);
5404 fw
->pfaend
= ufoImageUsed
;
5408 //==========================================================================
5412 //==========================================================================
5413 static void ufoDefineMisc (void) {
5414 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
5420 ufoNumber(16); UFC(BASE
); UFC(!);
5423 ufoDefine("DECIMAL");
5424 ufoNumber(10); UFC(BASE
); UFC(!);
5428 UFC(0) UFC(SWAP
) UFC(!)
5432 UFC(1) UFC(SWAP
) UFC(!)
5436 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(+) UFC(SWAP
) UFC(!)
5440 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(SWAP
) UFC(-) UFC(SWAP
) UFC(!)
5444 UFC(DUP
) UFC(@
) UFC(1+) UFC(SWAP
) UFC(!)
5448 UFC(DUP
) UFC(@
) UFC(2+) UFC(SWAP
) UFC(!)
5452 UFC(DUP
) UFC(@
) UFC(3+) UFC(SWAP
) UFC(!)
5456 UFC(DUP
) UFC(@
) UFC(4+) UFC(SWAP
) UFC(!)
5460 UFC(DUP
) UFC(@
) UFC(1-) UFC(SWAP
) UFC(!)
5464 UFC(DUP
) UFC(@
) UFC(2-) UFC(SWAP
) UFC(!)
5468 UFC(DUP
) UFC(@
) UFC(3-) UFC(SWAP
) UFC(!)
5472 UFC(DUP
) UFC(@
) UFC(4-) UFC(SWAP
) UFC(!)
5476 ufoNumber(0); UFC(=);
5480 ufoNumber(0); UFC(<>);
5484 ufoNumber(0); UFC(!=);
5488 ufoNumber(0); UFC(<);
5492 ufoNumber(0); UFC(>);
5496 ufoNumber(0); UFC(<=);
5500 ufoNumber(0); UFC(>=);
5504 ufoNumber(0); UFC(U
>);
5508 ufoNumber(1); UFC(=);
5512 ufoNumber(1); UFC(<>);
5516 ufoNumber(1); UFC(!=);
5520 ufoNumber(1); UFC(<);
5524 ufoNumber(1); UFC(>);
5528 ufoNumber(1); UFC(<=);
5532 ufoNumber(1); UFC(>=);
5536 ufoNumber(1); UFC(U
>);
5540 ufoNumber(1); UFC(U
<=);
5543 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
5547 //==========================================================================
5551 //==========================================================================
5552 static void ufoReset (void) {
5553 ufoWipeLocRecords();
5558 ufoSP
= 0; ufoRP
= 0;
5559 ufoLP
= 0; ufoLBP
= 0;
5563 ufoSetStateInterpret();
5565 ufoSetTIB(0); ufoSetIN(0);
5568 ufoColonWord
= NULL
;
5570 ufoDefaultVocFlags
= 0;
5572 ufoSetForthOnlyDefs();
5576 //==========================================================================
5580 //==========================================================================
5581 static void ufoInitCommon (void) {
5582 ufoForthDict
= NULL
;
5583 ufoColonWord
= NULL
;
5584 ufoLastVoc
= ~0U; ufoDefaultVocFlags
= 0;
5585 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
5587 ufoDStack
= calloc(UFO_DSTACK_SIZE
, sizeof(ufoDStack
[0]));
5588 ufoRStack
= calloc(UFO_RSTACK_SIZE
, sizeof(ufoRStack
[0]));
5589 ufoLStack
= calloc(UFO_LSTACK_SIZE
, sizeof(ufoLStack
[0]));
5590 ufoForthCFAs
= calloc(UFO_MAX_WORDS
, sizeof(ufoForthCFAs
[0]));
5591 // CFA 0 is reserved for FORTH vocabulary
5595 while (ufoImageUsed
<= ufoTIBAreaSize
) ufoImgEmitU32(0);
5598 ufoBASEaddr
= ufoImageUsed
;
5602 ufoSTATEaddr
= ufoImageUsed
;
5606 ufoAddrTIB
= ufoImageUsed
;
5610 ufoAddrIN
= ufoImageUsed
;
5614 ufoAddrContext
= ufoImageUsed
;
5618 ufoAddrCurrent
= ufoImageUsed
;
5621 ufoSetStateInterpret();
5623 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
5624 fw
->name
= strdup("FORTH");
5626 FW_SET_CFAIDX(fw
, 0); // known thing
5627 fw
->flags
= UFW_FLAG_PROTECTED
;
5628 fw
->pfa
= 0xffffffffU
;
5629 ufoForthVocCFA
= fw
->cfaidx
;
5630 ufoForthCFAs
[0] = fw
; // for proper links
5631 ufoCreateVocabData(fw
);
5632 // set CURRENT and CONTEXT
5633 ufoSetForthOnlyDefs();
5635 ufoLinkWordToDict(fw
);
5637 ufoDefaultVocFlags
= UFW_FLAG_PROTECTED
;
5639 UForthWord
*vcomp
= ufoCreateVocSetOnlyDefs("COMPILER", NULL
);
5640 ufoCompSuppVocCFA
= vcomp
->cfaidx
;
5641 ufoSetForthOnlyDefs();
5643 ufoMacroVocCFA
= ufoCreateVocSetOnlyDefs("URASM-MACROS", NULL
)->cfaidx
;
5644 ufoSetForthOnlyDefs();
5646 UForthWord
*vstr
= ufoCreateVocSetOnlyDefs("STRING", NULL
);
5647 ufoSetForthOnlyDefs();
5650 // base low-level interpreter words
5651 ufoDefineConstant("FALSE", 0);
5652 ufoDefineConstant("TRUE", ufoTrueValue
);
5654 ufoDefineConstant("BL", 32);
5655 ufoDefineConstant("NL", 10);
5657 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
5658 UFWORDX("SP0!", SP0_PUT
);
5659 UFWORDX("RP0!", RP0_PUT
);
5664 UFWORDX("C@", CPEEK
);
5665 UFWORDX("C!", CPOKE
);
5666 UFWORDX("W@", WPEEK
);
5667 UFWORDX("W!", WPOKE
);
5668 UFWORDX("C,", CCOMMA
);
5669 UFWORDX(",", COMMA
);
5671 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
5672 ufoVocSetOnlyDefs(vcomp
);
5674 UFWORDX("(BRANCH)", BRANCH
);
5675 UFWORDX("(TBRANCH)", TBRANCH
);
5676 UFWORDX("(0BRANCH)", 0BRANCH
);
5677 UFWORDX("(DO)", DO_PAREN
);
5678 UFWORDX("(LOOP)", LOOP_PAREN
);
5679 UFWORDX("(+LOOP)", PLOOP_PAREN
);
5681 // low-level compiler words
5682 UFWORDX("STRLITERAL", STRLITERAL
);
5684 UFWORDX("(\")", STRQ_PAREN
);
5685 UFWORDX("(.\")", STRDOTQ_PAREN
);
5687 UFWORDX("(EXIT)", PAR_EXIT
);
5688 UFWORDX("(L-ENTER)", PAR_LENTER
);
5689 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
5691 UFWORDX("?EXEC", QEXEC
);
5692 UFWORDX("?COMP", QCOMP
);
5693 UFWORDX("?PAIRS", QPAIRS
);
5694 UFWORDX("COMP-BACK", COMP_BACK
);
5695 UFWORDX("COMP-FWD", COMP_FWD
);
5697 UFWORDX("(LOCAL@)", LOCAL_LOAD
);
5698 UFWORDX("(LOCAL!)", LOCAL_STORE
);
5700 UFWORDX("(LOCAL@-1)", LOCAL_LOAD_1
);
5701 UFWORDX("(LOCAL@-2)", LOCAL_LOAD_2
);
5702 UFWORDX("(LOCAL@-3)", LOCAL_LOAD_3
);
5703 UFWORDX("(LOCAL@-4)", LOCAL_LOAD_4
);
5704 UFWORDX("(LOCAL@-5)", LOCAL_LOAD_5
);
5705 UFWORDX("(LOCAL@-6)", LOCAL_LOAD_6
);
5706 UFWORDX("(LOCAL@-7)", LOCAL_LOAD_7
);
5707 UFWORDX("(LOCAL@-8)", LOCAL_LOAD_8
);
5708 UFWORDX("(LOCAL@-9)", LOCAL_LOAD_9
);
5709 UFWORDX("(LOCAL@-10)", LOCAL_LOAD_10
);
5710 UFWORDX("(LOCAL@-11)", LOCAL_LOAD_11
);
5711 UFWORDX("(LOCAL@-12)", LOCAL_LOAD_12
);
5712 UFWORDX("(LOCAL@-13)", LOCAL_LOAD_13
);
5713 UFWORDX("(LOCAL@-14)", LOCAL_LOAD_14
);
5714 UFWORDX("(LOCAL@-15)", LOCAL_LOAD_15
);
5715 UFWORDX("(LOCAL@-16)", LOCAL_LOAD_16
);
5717 UFWORDX("(LOCAL!-1)", LOCAL_STORE_1
);
5718 UFWORDX("(LOCAL!-2)", LOCAL_STORE_2
);
5719 UFWORDX("(LOCAL!-3)", LOCAL_STORE_3
);
5720 UFWORDX("(LOCAL!-4)", LOCAL_STORE_4
);
5721 UFWORDX("(LOCAL!-5)", LOCAL_STORE_5
);
5722 UFWORDX("(LOCAL!-6)", LOCAL_STORE_6
);
5723 UFWORDX("(LOCAL!-7)", LOCAL_STORE_7
);
5724 UFWORDX("(LOCAL!-8)", LOCAL_STORE_8
);
5725 UFWORDX("(LOCAL!-9)", LOCAL_STORE_9
);
5726 UFWORDX("(LOCAL!-10)", LOCAL_STORE_10
);
5727 UFWORDX("(LOCAL!-11)", LOCAL_STORE_11
);
5728 UFWORDX("(LOCAL!-12)", LOCAL_STORE_12
);
5729 UFWORDX("(LOCAL!-13)", LOCAL_STORE_13
);
5730 UFWORDX("(LOCAL!-14)", LOCAL_STORE_14
);
5731 UFWORDX("(LOCAL!-15)", LOCAL_STORE_15
);
5732 UFWORDX("(LOCAL!-16)", LOCAL_STORE_16
);
5734 UFWORDX("(CODEBLOCK)", CODEBLOCK_PAR
);
5735 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
5736 ufoSetForthOnlyDefs();
5739 UFWORDX_IMM("RECURSE", RECURSE_IMM
);
5743 UFWORDX("?DUP", QDUP
);
5744 UFWORDX("2DUP", DDUP
);
5746 UFWORDX("2DROP", DDROP
);
5748 UFWORDX("2SWAP", DSWAP
);
5750 UFWORDX("2OVER", DOVER
);
5761 UFWORDX(">R", DTOR
);
5762 UFWORDX("R>", RTOD
);
5763 UFWORDX("R@", RPEEK
);
5765 UFWORDX("CMOVE>", CMOVE_FWD
);
5766 UFWORDX("CMOVE", CMOVE_BACK
);
5767 UFWORDX("MOVE", MOVE
);
5769 ufoVocSetOnlyDefs(vstr
);
5770 UFWORDX("=", STREQU
);
5771 UFWORDX("=CI", STREQUCI
);
5772 UFWORDX("CMP", STRCMP
);
5773 UFWORDX("CMP-CI", STRCMPCI
);
5774 UFWORDX("UNESCAPE", STR_UNESCAPE
);
5775 ufoSetForthOnlyDefs();
5777 // some useful words
5778 UFWORDX_IMM("(", COMMENTPAREN
);
5779 UFWORDX_IMM("\\", COMMENTEOL
);
5780 UFWORDX_IMM(";;", COMMENTEOL
);
5781 UFWORDX_IMM("(*", COMMENTML
);
5782 UFWORDX_IMM("((", COMMENTML_NESTED
);
5793 UFWORDX("LASTCR?", LASTCRQ
);
5794 UFWORDX("LASTCR!", LASTCRSET
);
5798 UFWORDX("U.", UDOT
);
5799 UFWORDX(".R", DOTR
);
5800 UFWORDX("U.R", UDOTR
);
5805 UFWORDX("-", MINUS
);
5807 UFWORDX("U*", UMUL
);
5809 UFWORDX("U/", UDIV
);
5810 UFWORDX("MOD", MOD
);
5811 UFWORDX("UMOD", UMOD
);
5812 UFWORDX("/MOD", DIVMOD
);
5813 UFWORDX("U/MOD", UDIVMOD
);
5817 UFWORDX(">", GREAT
);
5818 UFWORDX("<=", LESSEQU
);
5819 UFWORDX(">=", GREATEQU
);
5820 UFWORDX("U<", ULESS
);
5821 UFWORDX("U>", UGREAT
);
5822 UFWORDX("U<=", ULESSEQU
);
5823 UFWORDX("U>=", UGREATEQU
);
5826 UFWORDX("BOUNDS?", BOUNDSQ
);
5829 UFWORDX("<>", NOTEQU
);
5830 UFWORDX("!=", NOTEQU
);
5835 UFWORDX("LOGAND", LOGAND
);
5837 UFWORDX("LOGOR", LOGOR
);
5840 UFWORDX("1+", ONEPLUS
);
5841 UFWORDX("1-", ONEMINUS
);
5842 UFWORDX("2+", TWOPLUS
);
5843 UFWORDX("2-", TWOMINUS
);
5844 UFWORDX("3+", THREEPLUS
);
5845 UFWORDX("3-", THREEMINUS
);
5846 UFWORDX("4+", FOURPLUS
);
5847 UFWORDX("4-", FOURMINUS
);
5848 UFWORDX("2U*", ONESHL
);
5849 UFWORDX("2U/", ONESHR
);
5854 UFWORDX_IMM("\"", STRQ
);
5855 UFWORDX_IMM(".\"", STRDOTQ
);
5857 UFWORDX("LITERAL", LITERAL
);
5858 UFWORDX_IMM("COMPILE", COMPILE_IMM
);
5859 UFWORDX_IMM("[COMPILE]", XCOMPILE_IMM
);
5860 UFWORDX_IMM("[']", XTICK_IMM
);
5861 UFWORDX_IMM("['PFA]", XTICKPFA_IMM
);
5863 UFWORDX_IMM("'", TICK_IMM
);
5864 UFWORDX_IMM("'PFA", TICKPFA_IMM
);
5866 UFWORDX_IMM("EXIT", EXIT_IMM
);
5872 UFWORDX_IMM("THEN", ENDIF
);
5876 UFWORDX_IMM("NOT-WHILE", NOT_WHILE
);
5877 UFWORDX_IMM("REPEAT", AGAIN
);
5879 UFWORDX_IMM("NOT-UNTIL", NOT_UNTIL
);
5881 UFWORD_IMM(ENDCASE
);
5883 UFWORDX_IMM("&OF", AND_OF
);
5885 UFWORD_IMM(OTHERWISE
);
5888 UFWORDX_IMM("+LOOP", PLOOP
);
5891 UFWORDX("I'", ITICK
);
5892 UFWORDX("J'", JTICK
);
5894 UFWORDX(":", COLON
);
5895 UFWORDX_IMM(";", SEMI
);
5897 UFWORDX("CREATE;", CREATE_SEMI
);
5898 UFWORDX("DOES>", DOES
);
5901 UFWORDX_IMM("VOCID:", VOCID_IMM
);
5905 UFWORD(DEFINITIONS
);
5906 UFWORDX("NESTED-VOCABULARY", NESTED_VOCABULARY
);
5907 UFWORDX("<PUBLIC-WORDS>", VOC_PUBLIC_MODE
);
5908 UFWORDX("<HIDDEN-WORDS>", VOC_HIDDEN_MODE
);
5909 UFWORDX("<PROTECTED-WORDS>", VOC_PROTECTED_MODE
);
5910 UFWORDX("<UNPROTECTED-WORDS>", VOC_UNPROTECTED_MODE
);
5912 UFWORDX("(PROTECTED)", PAR_PROTECTED
);
5913 UFWORDX("(HIDDEN)", PAR_HIDDEN
);
5915 UFWORDX_IMM("LOCALS:", LOCALS_IMM
);
5916 UFWORDX_IMM("ARGS:", ARGS_IMM
);
5919 UFWORDX("(PARSE)", PAR_PARSE
);
5920 UFWORDX("(WORD-OR-PARSE)", PAR_WORD_OR_PARSE
);
5922 UFWORDX("PARSE-TO-HERE", PARSE_TO_HERE
);
5923 UFWORDX("PARSE-NAME", PARSE_NAME
);
5924 UFWORDX("PARSE", PARSE
);
5926 UFWORDX("TIB-ADVANCE-LINE", TIB_ADVANCE_LINE
);
5927 UFWORDX("TIB-CHAR?", TIB_PEEKCH
);
5928 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
5929 UFWORDX("TIB-GETCH", TIB_GETCH
);
5930 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
5932 UFWORDX(">IN", GET_IN_ADDR
);
5933 UFWORDX("TIB", GET_TIB_ADDR
);
5934 UFWORDX("TIB-SIZE", GET_TIB_SIZE
);
5938 UFWORDX("(NUMBER)", XNUMBER
);
5941 UFWORDX("VALUE", VALUE
);
5942 UFWORDX("VAR-NOALLOT", VAR_NOALLOT
);
5943 UFWORDX("VARIABLE", VARIABLE
);
5944 UFWORDX("CONSTANT", CONSTANT
);
5945 UFWORDX("DEFER", DEFER
);
5946 UFWORDX("LOAD-DATA-FILE", LOAD_DATA_FILE
);
5947 UFWORDX("N-ALLOT", N_ALLOT
);
5948 UFWORDX("ALLOT", ALLOT
);
5949 UFWORDX("HERE", HERE
);
5950 UFWORDX("PAD", PAD
);
5951 UFWORDX_IMM("TO", TO_IMM
);
5952 UFWORDX("NAMED-TO", NAMED_TO
);
5953 UFWORDX("CFA->PFA", CFA2PFA
);
5955 UFWORDX_IMM("[", LSQBRACKET_IMM
);
5956 UFWORDX("]", RSQBRACKET
);
5958 UFWORDX_IMM("[:", CODEBLOCK_START_IMM
);
5959 UFWORDX_IMM(";]", CODEBLOCK_END_IMM
);
5960 /* code blocks are used like this:
5961 : A [: ( addr count -- res ) TYPE 0 ;] ASM-FOREACH-LABEL DROP ;
5962 i.e. it creates inlined code block, and returns its CFA.
5967 (void)ufoCreateVocSetOnlyDefs("URASM", NULL
);
5968 // UrAsm label types
5969 // WARNING! keep in sync with C source!
5970 ufoDefineConstant("LBL-TYPE-UNKNOWN", UFO_ZX_LABEL_UNKNOWN
);
5971 ufoDefineConstant("LBL-TYPE-VAR", UFO_ZX_LABEL_VAR
);
5972 ufoDefineConstant("LBL-TYPE-EQU", UFO_ZX_LABEL_EQU
);
5973 ufoDefineConstant("LBL-TYPE-CODE", UFO_ZX_LABEL_CODE
);
5974 ufoDefineConstant("LBL-TYPE-STOFS", UFO_ZX_LABEL_STOFS
);
5975 ufoDefineConstant("LBL-TYPE-DATA", UFO_ZX_LABEL_DATA
);
5977 UFWORDX("C,", ZX_CCOMMA
);
5978 UFWORDX("W,", ZX_WCOMMA
);
5979 UFWORDX("C@", ZX_CPEEK
);
5980 UFWORDX("C!", ZX_CPOKE
);
5981 UFWORDX("W@", ZX_WPEEK
);
5982 UFWORDX("W!", ZX_WPOKE
);
5984 UFWORDX("RESERVED?", ZX_RESERVEDQ
);
5985 UFWORDX("RESERVED!", ZX_RESERVEDS
);
5987 UFWORDX("HAS-LABEL?", UR_HAS_LABELQ
);
5988 UFWORDX("LABEL-TYPE?", UR_GET_LABELQ_TYPE
);
5989 UFWORDX("GET-LABEL", UR_GET_LABELQ
);
5990 UFWORDX("FOREACH-LABEL", UR_FOREACH_LABEL
);
5991 UFWORDX("SET-LABEL-VAR", UR_SET_LABEL_VAR
);
5992 UFWORDX("SET-LABEL-EQU", UR_SET_LABEL_EQU
);
5993 UFWORDX("SET-LABEL-CODE", UR_SET_LABEL_CODE
);
5994 UFWORDX("SET-LABEL-STOFS", UR_SET_LABEL_STOFS
);
5995 UFWORDX("SET-LABEL-DATA", UR_SET_LABEL_DATA
);
5996 UFWORDX("PASS@", UR_PASSQ
);
5998 UFWORDX("LOAD-DATA-FILE", ZX_LOAD_DATA_FILE
);
6000 UFWORDX("ORG@", UR_GETORG
);
6001 UFWORDX("DISP@", UR_GETDISP
);
6002 UFWORDX("ENT@", UR_GETENT
);
6003 UFWORDX("ORG!", UR_SETORG
);
6004 UFWORDX("DISP!", UR_SETDISP
);
6005 UFWORDX("ENT!", UR_SETENT
);
6007 UFWORDX("WARNING", ASM_WARNING
);
6008 UFWORDX("ERROR", ASM_ERROR
);
6009 ufoSetForthOnlyDefs();
6012 // conditional compilation
6013 UFWORDX_IMM("$IF", DLR_IF_IMM
);
6014 UFWORDX_IMM("$ELSE", DLR_ELSE_IMM
);
6015 UFWORDX_IMM("$ELIF", DLR_ELIF_IMM
);
6016 UFWORDX_IMM("$ENDIF", DLR_ENDIF_IMM
);
6018 UFWORDX_IMM("$DEFINE", DLR_DEFINE
);
6019 UFWORDX_IMM("$UNDEF", DLR_UNDEF
);
6021 UFWORDX_IMM("$LABEL-DATA:", DLR_LABEL_DATA_IMM
);
6022 UFWORDX_IMM("$LABEL-CODE:", DLR_LABEL_CODE_IMM
);
6024 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE
);
6025 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE
);
6027 UFWORDX("INCLUDE", INCLUDE
);
6030 (void)ufoCreateVocSetOnlyDefs("UFO", NULL
);
6031 UFWORDX("FATAL", UFO_FATAL
);
6033 // UrForth internal word types
6034 ufoDefineConstant("WTYPE-NONE", 0);
6035 ufoDefineConstant("WTYPE-CODE", 1);
6036 ufoDefineConstant("WTYPE-FORTH", 2);
6037 ufoDefineConstant("WTYPE-VARIABLE", 3);
6038 ufoDefineConstant("WTYPE-VALUE", 4);
6039 ufoDefineConstant("WTYPE-CONSTANT", 5);
6040 ufoDefineConstant("WTYPE-DEFER", 6);
6041 ufoDefineConstant("WTYPE-DOES", 7);
6042 ufoDefineConstant("WTYPE-VOCABULARY", 8);
6044 UFWORDX("WORDS-ITER-NEW", WORDS_ITER_NEW
);
6045 UFWORDX("WORDS-ITER-PREV", WORDS_ITER_PREV
);
6046 UFWORDX("WORDS-ITER-NAME", WORDS_ITER_NAME
);
6047 UFWORDX("WORDS-ITER-PFA", WORDS_ITER_PFA
);
6048 UFWORDX("WORDS-ITER-IMM?", WORDS_ITER_IMMQ
);
6049 UFWORDX("WORDS-ITER-PROT?", WORDS_ITER_PROTQ
);
6050 UFWORDX("WORDS-ITER-HIDDEN?", WORDS_ITER_HIDDENQ
);
6051 UFWORDX("WORDS-ITER-TYPE?", WORDS_ITER_TYPEQ
);
6052 UFWORDX("FOREACH-WORD", UFO_FOREACH_WORD
);
6054 UFWORDX("<MODE@>", UFO_MODER
);
6056 ufoSetForthOnlyDefs();
6059 (void)ufoCreateVocSetOnlyDefs("DEBUG", NULL
);
6060 UFWORDX("DUMP-STACK", DUMP_STACK
);
6061 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
6062 UFWORDX("DECOMPILE", UFO_DECOMPILE_INTERNAL
);
6063 UFWORDX("BP", UFO_BP
);
6064 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
6065 ufoSetForthOnlyDefs();
6071 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6074 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
6076 UFWORDX_IMM("$END_FORTH", DLR_END_FORTH
);
6077 UFWORDX_IMM("$END-FORTH", DLR_END_FORTH
);
6078 //UFWORDX("$END-FORTH", DLR_END_FORTH_NOIMM);
6081 UFWORDX("ZXADDR?", ZXADDRQ
);
6082 UFWORDX("(TOZX)", TOZX
);
6083 UFWORDX_IMM("TOZX", TOZX_IMM
);
6084 UFWORDX("(FROMZX)", FROMZX
);
6085 UFWORDX_IMM("FROMZX", FROMZX_IMM
);
6089 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6093 //==========================================================================
6097 // address interpreter
6099 //==========================================================================
6100 static void ufoRunVM (void) {
6102 while (!ufoStopVM
) {
6103 uint32_t cfaidx
= ufoImgGetU32(ufoIP
++);
6104 if (cfaidx
& UFO_RS_CFA_BIT
) {
6105 cfaidx
&= UFO_RS_CFA_MASK
;
6106 if (cfaidx
>= ufoCFAsUsed
) {
6107 ufoFatal("UFO tried to execute an unknown word: 0x%08x (max is 0x%08x); IP=0x%08x", cfaidx
, ufoCFAsUsed
, ufoIP
-1);
6109 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
6110 if (fw
== NULL
) ufoFatal("VM internal error: empty CFA");
6113 ufoFatal("VM tried to execute something that is not a word");
6120 //==========================================================================
6124 //==========================================================================
6125 static void ufoRunIt (const char *wname
) {
6126 UForthWord
*fw
= ufoAlwaysWord(wname
);
6127 if (fw
->cfa
!= &ufoDoForth
) {
6128 ufoFatal("UFO '%s' word is not a Forth word", wname
);
6130 ufoExecuteNativeWordInVM(fw
);
6134 //==========================================================================
6138 //==========================================================================
6139 void ufoInlineInit (void) {
6140 ufoMode
= UFO_MODE_NATIVE
;
6141 ufoTrueValue
= ~0u; // -1 is better!
6143 ufoInFileLine
= 0; ufoCondStLine
= -1;
6144 ufoInFileName
= NULL
;
6146 ufoLastIncPath
= NULL
;
6150 ufoSetStateInterpret();
6157 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
6158 FILE *ufl
= ufoOpenFileOrDir(&ufmname
);
6161 ufoInFileName
= ufmname
;
6163 setLastIncPath(ufoInFileName
);
6170 //==========================================================================
6174 //==========================================================================
6175 void ufoInlineRun (void) {
6176 if (ufoMode
== UFO_MODE_NONE
) {
6179 ufoMode
= UFO_MODE_NATIVE
;
6181 if (setjmp(ufoInlineQuitJP
) == 0) {
6183 //UFCALL(INTERPRET);
6184 ufoRunIt("UFO-RUN-LOOP");
6185 ufo_assert(0); // the thing that should not be
6187 while (ufoFileStackPos
!= 0) ufoPopInFile();
6192 //==========================================================================
6196 //==========================================================================
6197 uint32_t ufoIsMacro (const char *wname
) {
6198 if (ufoMode
!= UFO_MODE_NONE
) {
6199 UForthWord
*fw
= ufoFindWordMacro(wname
);
6200 if (fw
!= NULL
&& fw
->cfa
== &ufoDoForth
) return fw
->cfaidx
;
6206 //==========================================================================
6210 //==========================================================================
6211 void ufoMacroRun (uint32_t cfaidx
, const char *line
, const char *fname
, int lnum
) {
6212 ufo_assert(ufoMode
!= UFO_MODE_NONE
);
6213 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfaidx
);
6214 ufoMode
= UFO_MODE_MACRO
;
6215 if (fw
->cfa
!= &ufoDoForth
) {
6216 ufoFatal("UFO '%s' macro word is not a Forth word", fw
->name
);
6219 if (setjmp(ufoInlineQuitJP
) == 0) {
6221 ufoLoadMacroLine(line
, fname
, lnum
);
6222 ufoExecuteNativeWordInVM(fw
);
6223 while (ufoFileStackPos
!= 0) ufoPopInFile();
6225 while (ufoFileStackPos
!= 0) ufoPopInFile();
6226 ufoFatal("wtf with UFO macro?!");