1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
5 //#define UFO_UPPERCASE_DICT_WORDS
8 //#define UFO_DEBUG_FATAL_ABORT
9 //#define UFO_DEBUG_PARSE
10 //#define UFO_DEBUG_INLCUDE
13 #define UFO_FORCE_INLINE static inline __attribute__((always_inline))
14 #define UFO_INLINE static inline
17 #define UFO_QPAIRS_BEGIN (1)
18 #define UFO_QPAIRS_IF (2)
19 #define UFO_QPAIRS_DO (3)
20 #define UFO_QPAIRS_CASE (4)
21 #define UFO_QPAIRS_OF (5)
22 #define UFO_QPAIRS_OTHER (6)
23 #define UFO_QPAIRS_WHILE (7)
24 #define UFO_QPAIRS_CBLOCK (666)
26 // should not be bigger than this!
27 #define UFO_MAX_WORD_LENGTH (127)
30 //==========================================================================
34 //==========================================================================
35 UFO_FORCE_INLINE
uint32_t joaatHashBufCI (const void *buf
, size_t len
) {
36 uint32_t hash
= 0x29a;
37 const uint8_t *s
= (const uint8_t *)buf
;
39 //hash += (uint8_t)locase1251(*s++);
40 hash
+= (*s
++)|0x20; // this converts ASCII capitals to locase (and destroys other, but who cares)
52 #define UFW_FLAG_IMMEDIATE (1u<<0)
53 #define UFW_FLAG_PROTECTED (1u<<1)
54 #define UFW_FLAG_HIDDEN (1u<<2)
55 #define UFW_FLAG_VOC_HIDDEN (1u<<3)
57 #define UFW_IS_IMM(fw_) (((fw_)->flags&UFW_FLAG_IMMEDIATE) != 0)
58 #define UFW_IS_PROT(fw_) (((fw_)->flags&UFW_FLAG_PROTECTED) != 0)
59 #define UFW_IS_HID(fw_) (((fw_)->flags&UFW_FLAG_HIDDEN) != 0)
60 #define UFW_IS_VOC_HID(fw_) (((fw_)->flags&UFW_FLAG_VOC_HIDDEN) != 0)
63 typedef struct UForthWord_t UForthWord
;
66 UForthWord
*prevAll
; // in global list
67 UForthWord
*prevVoc
; // in vocabulary
68 void (*cfa
) (UForthWord
*self
); // `self` may be NULL if called from the internal code
69 uint32_t cfaidx
; // in `ufoForthCFAs`
70 uint32_t pfastart
; // pointer to image
71 uint32_t pfaend
; // set in `;`
72 uint32_t pfa
; // pointer to image
73 uint32_t flags
; // see `UFW_FLAG_xxx`
74 // parent vocabulary link (for vocabularies only)
76 UForthWord
**buckets
; // vocabulary hash table
77 // hash and bucket link
82 #define UFO_DICT_HASH_BUCKETS (1024u)
83 static UForthWord
*ufoForthDict
= NULL
;
84 static UForthWord
*ufoColonWord
= NULL
;
86 static jmp_buf ufoInlineQuitJP
;
88 #define UFO_MAX_WORDS (65536u)
89 static UForthWord
**ufoForthCFAs
= NULL
;
90 static unsigned ufoCFAsUsed
= 0;
92 #define UFO_ZX_ADDR_BIT (1u<<30)
93 #define UFO_ZX_ADDR_MASK (0xffffU)
95 #define UFO_RS_CFA_BIT (1u<<31)
96 #define UFO_RS_CFA_MASK ((1u<<31)-1u)
98 #define UFO_ENSURE_NATIVE_ADDR(adr_) do { \
99 const uint32_t aa = (uint32_t)(adr_); \
100 if (aa & UFO_ZX_ADDR_BIT) ufoFatal("unexpected ZX address"); \
101 if (aa & UFO_RS_CFA_BIT) ufoFatal("unexpected CFA address"); \
104 #define UFO_ENSURE_NATIVE_CFA(adr_) ({ \
105 const uint32_t aa = (uint32_t)(adr_); \
106 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
107 if ((aa&UFO_RS_CFA_MASK) >= ufoCFAsUsed || ufoForthCFAs[(aa&UFO_RS_CFA_MASK)] == NULL) ufoFatal("invalid CFA address"); \
111 #define UFO_GET_NATIVE_CFA(adr_) ({ \
112 uint32_t aa = (uint32_t)(adr_); \
113 if ((aa & UFO_RS_CFA_BIT) == 0) ufoFatal("expected CFA address"); \
114 aa &= UFO_RS_CFA_MASK; \
115 if (aa >= ufoCFAsUsed || ufoForthCFAs[aa] == NULL) ufoFatal("invalid CFA address"); \
119 #define FW_GET_CFAIDX(fw_) ((fw_)->cfaidx & UFO_RS_CFA_MASK)
120 #define FW_SET_CFAIDX(fw_,ci_) ((fw_)->cfaidx = (((ci_) & UFO_RS_CFA_MASK) | UFO_RS_CFA_BIT))
122 static uint32_t *ufoImage
= NULL
;
123 static uint32_t ufoImageSize
= 0;
124 static uint32_t ufoImageUsed
= 0;
126 static uint32_t ufoIP
= 0; // in image
127 static uint32_t ufoSP
= 0; // points AFTER the last value pushed
128 static uint32_t ufoRP
= 0; // points AFTER the last value pushed
129 static uint32_t ufoRPTop
= 0; // stop when RP is this, and we're doing EXIT
131 static uint32_t ufoTrueValue
= ~0u;
133 // the compiler works in two modes
134 // first mode is "native"
135 // only forth variables are allowed, and they're leaving ZX addresses
136 // second mode is "zx"
137 // in this mode, various creation words will create things in ZX memory.
138 // note that in interpret mode it is still possible to perform various
139 // native calculations, and call native words.
140 // but calling native word while compiling ZX code is possible only if it
141 // is an immediate one.
144 UFO_MODE_NATIVE
= 0, // executing forth code
145 UFO_MODE_MACRO
= 1, // executing forth asm macro
147 static uint32_t ufoMode
= UFO_MODE_NONE
;
149 // hack for `IMMEDIATE`
151 // only one of those can be set! (invariant)
152 static UForthWord
*ufoLastDefinedNativeWord
= NULL
;
154 #define UFO_DSTACK_SIZE (8192)
155 #define UFO_RSTACK_SIZE (8192)
156 static uint32_t *ufoDStack
= NULL
;
157 static uint32_t *ufoRStack
= NULL
;
160 typedef struct UForthLocRecord_t
{
161 char name
[128]; // local name
162 uint32_t lidx
; // offset from the current local ptr
163 struct UForthLocRecord_t
*next
;
166 #define UFO_LSTACK_SIZE (8192)
167 static uint32_t *ufoLStack
= NULL
;
168 static uint32_t ufoLP
, ufoLBP
; // bottom, base; nice names, yeah
169 // used in the compiler
170 static UForthLocRecord
*ufoLocals
= NULL
;
172 // dynamically allocated text input buffer
173 // always ends with zero (this is word name too)
174 // first 512 cells of image is TIB
175 static uint32_t ufoTIBAreaSize
= 512;
177 static uint32_t ufoAddrTIB
= 0; // TIB; 0 means "in TIB area", otherwise in the dictionary
178 static uint32_t ufoAddrIN
= 0; // >IN
180 static uint32_t ufoAddrContext
= 0; // CONTEXT
181 static uint32_t ufoAddrCurrent
= 0; // CURRENT
182 static uint32_t ufoDefaultVocFlags
= 0;
183 static uint32_t ufoLastVoc
= 0;
185 static uint32_t ufoBASEaddr
; // address of "BASE" variable
186 static uint32_t ufoSTATEaddr
; // address of "STATE" variable
187 static uint32_t ufoStopVM
;
188 static int ufoInColon
; // should be signed
190 #define UFO_PAD_OFFSET (2048u)
191 #define UFO_PAD1_OFFSET (4096u)
193 #define UFO_MAX_NESTED_INCLUDES (32)
199 uint32_t savedTIBSize
;
202 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
203 static uint32_t ufoFileStackPos
; // after the last used item
205 static FILE *ufoInFile
= NULL
;
206 static char *ufoInFileName
= NULL
;
207 static int ufoInFileLine
= 0;
208 static int ufoCondStLine
= -1;
209 static UrLabelInfo
*zxlblLastByte
= NULL
;
211 static int ufoLastEmitWasCR
= 1;
212 static uint32_t ufoCSP
= 0;
213 static int ufoInCondIf
= 0;
215 #define UFO_VOCSTACK_SIZE (16u)
216 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
217 static uint32_t ufoVSP
;
218 static uint32_t ufoForthVocCFA
;
219 static uint32_t ufoCompSuppVocCFA
;
220 static uint32_t ufoMacroVocCFA
;
222 static char ufoCurrFileLine
[520];
223 // used to extract strings from the image
224 static char ufoTempCharBuf
[1024];
227 // ////////////////////////////////////////////////////////////////////////// //
229 static void ufoDbgDeinit (void);
231 static void ufoClearCondDefines (void);
232 static void ufoRunVM (void);
234 static int ufoParseConditionExpr (int doskip
);
237 // ////////////////////////////////////////////////////////////////////////// //
238 UFO_FORCE_INLINE
uint32_t ufoPadAddr (void) {
239 return (ufoImageUsed
+ UFO_PAD_OFFSET
+ 1023u) / 1024u * 1024u;
243 static void ufoDoForth (UForthWord
*self
);
244 static void ufoDoVariable (UForthWord
*self
);
245 static void ufoDoValue (UForthWord
*self
);
246 static void ufoDoConst (UForthWord
*self
);
247 static void ufoDoDefer (UForthWord
*self
);
248 static void ufoDoVoc (UForthWord
*self
);
251 //==========================================================================
255 //==========================================================================
256 static void ufoErrorWriteFile (FILE *fo
) {
258 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
260 fprintf(fo
, "UFO ERROR somewhere in time: ");
265 //==========================================================================
269 //==========================================================================
270 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
271 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
273 ufoErrorWriteFile(stderr
);
274 vfprintf(stderr
, fmt
, ap
);
281 //==========================================================================
285 //==========================================================================
286 static void ufoStackTrace (void) {
287 // dump data stack (top 16)
288 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
289 uint32_t xsp
= ufoSP
;
290 if (xsp
> 16) xsp
= 16;
291 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
292 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
293 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
295 //if (ufoSP != 0) fputc('\n', stderr);
297 // dump return stack (top 32)
298 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
300 uint32_t rscount
= 0;
301 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
302 while (rscount
!= 32 && rp
!= 0) {
304 uint32_t cfa
= ufoRStack
[rp
];
305 if (cfa
& UFO_RS_CFA_BIT
) {
306 cfa
&= UFO_RS_CFA_MASK
;
307 if (cfa
< ufoCFAsUsed
&& ufoForthCFAs
[cfa
] != NULL
) {
308 UForthWord
*fw
= ufoForthCFAs
[cfa
];
309 fprintf(stderr
, " %2u: %s\n", rscount
, fw
->name
);
311 fprintf(stderr
, " %2u: wutafuck?\n", rscount
);
321 //==========================================================================
325 //==========================================================================
326 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2))) \
327 static void ufoFatal (const char *fmt
, ...) {
330 ufoErrorMsgV(fmt
, ap
);
332 #ifdef UFO_DEBUG_FATAL_ABORT
339 //==========================================================================
343 //==========================================================================
344 static void ufoWipeLocRecords (void) {
345 while (ufoLocals
!= NULL
) {
346 UForthLocRecord
*r
= ufoLocals
;
347 ufoLocals
= ufoLocals
->next
;
353 //==========================================================================
357 // return !0 for duplicate
359 //==========================================================================
360 static void ufoNewLocal (const char *name
) {
363 if (name
== NULL
|| name
[0] == 0) ufoFatal("empty local name");
364 const size_t nlen
= strlen(name
);
365 if (nlen
> 127) ufoFatal("local name too long");
366 for (size_t f
= 0; f
< nlen
; f
+= 1) {
368 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
369 //if (ch == ':' || ch == '!') ufoFatal("invalid local name '%s'", name);
374 UForthLocRecord
*r
= ufoLocals
;
375 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
377 if (r
!= NULL
) ufoFatal("duplocate local '%s'", name
);
379 r
= calloc(1, sizeof(*r
));
380 strcpy(r
->name
, buf
);
381 if (ufoLocals
== 0) r
->lidx
= 1; else r
->lidx
= ufoLocals
->lidx
+ 1;
382 r
->next
= ufoLocals
; ufoLocals
= r
;
386 //==========================================================================
390 //==========================================================================
391 static UForthLocRecord
*ufoFindLocal (const char *name
, int *wantStore
) {
394 if (wantStore
) *wantStore
= 0;
395 if (name
== NULL
|| name
[0] != ':' || name
[1] == 0) return NULL
;
396 name
+= 1; // skip colon
397 size_t nlen
= strlen(name
);
398 if (nlen
!= 0 && name
[nlen
- 1] == '!') {
399 if (wantStore
) *wantStore
= 1;
401 if (nlen
== 0) return NULL
;
403 if (nlen
> 127) return NULL
;
404 for (size_t f
= 0; f
< nlen
; f
+= 1) {
406 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+'A';
411 UForthLocRecord
*r
= ufoLocals
;
412 while (r
!= NULL
&& strcmp(r
->name
, buf
) != 0) r
= r
->next
;
418 // ////////////////////////////////////////////////////////////////////////// //
419 // working with the zx image
421 //==========================================================================
425 //==========================================================================
426 UFO_FORCE_INLINE
uint32_t ufoZXGetU8 (uint32_t addr
) {
428 return getByte(addr
);
432 //==========================================================================
436 //==========================================================================
437 UFO_FORCE_INLINE
void ufoZXPutU8 (uint32_t addr
, uint32_t v
) {
444 //==========================================================================
448 //==========================================================================
449 UFO_FORCE_INLINE
uint32_t ufoZXGetU16 (uint32_t addr
) {
451 return getWord(addr
);
455 //==========================================================================
459 //==========================================================================
460 UFO_FORCE_INLINE
void ufoZXPutU16 (uint32_t addr
, uint32_t v
) {
467 //==========================================================================
471 //==========================================================================
472 UFO_FORCE_INLINE
void ufoZXEmitU8 (uint32_t v
) {
473 //if (!zxlblLastByte) ufoFatal("label 'latest_byte' not found");
475 if (zxlblLastByte
) zxlblLastByte
->value
= disp
;
479 //==========================================================================
483 //==========================================================================
484 UFO_FORCE_INLINE
void ufoZXEmitU16 (uint32_t v
) {
485 //if (!zxlblLastByte) ufoFatal("label 'latest_byte' not found");
487 if (zxlblLastByte
) zxlblLastByte
->value
= disp
;
491 // ////////////////////////////////////////////////////////////////////////// //
492 // working with the image
494 //==========================================================================
498 //==========================================================================
499 static void ufoImgEnsureSize (uint32_t addr
) {
500 UFO_ENSURE_NATIVE_ADDR(addr
);
501 if (addr
>= ufoImageSize
) {
502 // 256MB should be enough for everyone!
503 // one cell is 4 bytes, so max address is 64MB
504 if (addr
>= 0x04000000U
) {
506 ufoFatal("UFO image grown too big (addr=0%08XH)", addr
);
508 const uint32_t osz
= ufoImageSize
;
509 // grow by 4MB steps (16 real MBs)
510 uint32_t nsz
= (addr
|0x003fffffU
) + 1U;
511 uint32_t *nimg
= realloc(ufoImage
, nsz
* sizeof(ufoImage
[0]));
513 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
514 ufoImageSize
/ 1024u / 1024u,
515 nsz
/ 1024u / 1024u);
519 memset(ufoImage
+ osz
, 0, (nsz
- osz
) * sizeof(ufoImage
[0]));
524 //==========================================================================
528 //==========================================================================
529 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, uint32_t value
) {
530 UFO_ENSURE_NATIVE_ADDR(addr
);
531 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
532 ufoImage
[addr
] = value
&0xffU
;
536 //==========================================================================
540 //==========================================================================
541 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, uint32_t value
) {
542 UFO_ENSURE_NATIVE_ADDR(addr
);
543 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
544 ufoImage
[addr
] = value
;
548 //==========================================================================
552 //==========================================================================
553 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
554 ufoImgPutU8(ufoImageUsed
, value
);
559 //==========================================================================
563 //==========================================================================
564 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
565 ufoImgPutU32(ufoImageUsed
, value
);
570 //==========================================================================
574 //==========================================================================
575 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
576 UFO_ENSURE_NATIVE_ADDR(addr
);
577 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
578 return ufoImage
[addr
]&0xffU
;
582 //==========================================================================
586 //==========================================================================
587 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
588 UFO_ENSURE_NATIVE_ADDR(addr
);
589 if (addr
>= ufoImageSize
) ufoFatal("UFO read violation (%u)", addr
);
590 return ufoImage
[addr
];
594 //==========================================================================
598 // 32 for native address
600 //==========================================================================
601 UFO_FORCE_INLINE
uint32_t ufoImgGetCounter (uint32_t addr
) {
602 UFO_ENSURE_NATIVE_ADDR(addr
);
603 return ufoImgGetU32(addr
);
607 //==========================================================================
609 // ufoCreateIncludeName
611 // returns malloced string
613 //==========================================================================
614 static char *ufoCreateIncludeName (const char *fname
, int assystem
) {
615 if (!fname
|| !fname
[0]) return strdup("");
616 //char *incdir = extractFileDir(ufoInFileName);
619 if (!assystem
&& stat(fname
, &st
) == 0) return strdup(fname
);
621 if (fname
[0] == '/') return strdup(fname
);
625 incdir
= (ufoIncludeDir
&& ufoIncludeDir
[0] ? strprintf("%s", ufoIncludeDir
) : strdup("."));
627 incdir
= extractFileDir(ufoInFileName
);
629 char *res
= strprintf("%s/%s", incdir
, fname
);
631 fprintf(stderr
, "000: **** <%s> : <%s> : <%s>\n", fname
, incdir
, res
);
634 if (stat(res
, &st
) == 0) return res
;
636 return strdup(fname
);
640 //==========================================================================
644 //==========================================================================
645 static FILE *ufoOpenFileOrDir (char **fnameptr
) {
650 if (fnameptr
== NULL
) return NULL
;
653 fprintf(stderr
, "***:fname=<%s>\n", fname
);
656 if (fname
== NULL
|| fname
[0] == 0 || stat(fname
, &st
) != 0) return NULL
;
658 if (S_ISDIR(st
.st_mode
)) {
659 tmp
= calloc(1, strlen(fname
) + 128);
660 if (tmp
== NULL
) { fprintf(stderr
, "UFO: out of memory!\n"); abort(); }
661 sprintf(tmp
, "%s/%s", fname
, "zzmain.f");
662 free(fname
); fname
= tmp
; *fnameptr
= tmp
;
664 fprintf(stderr
, "***: <%s>\n", fname
);
668 return fopen(fname
, "rb");
672 //==========================================================================
676 //==========================================================================
677 static void ufoPushInFile (void) {
678 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
679 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
681 stk
->fname
= ufoInFileName
;
682 stk
->fline
= ufoInFileLine
;
683 // save TIB (if it is the default)
684 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
685 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
686 stk
->savedTIBSize
= 0;
687 stk
->savedTIB
= NULL
;
688 if (tib
== 0 && in
< ufoTIBAreaSize
) {
689 while (ufoImgGetU8(tib
+ in
+ stk
->savedTIBSize
) != 0) stk
->savedTIBSize
+= 1;
690 if (stk
->savedTIBSize
!= 0) {
691 stk
->savedTIB
= malloc(stk
->savedTIBSize
);
692 if (stk
->savedTIB
== NULL
) ufoFatal("out of memory for include stack");
693 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
694 stk
->savedTIB
[f
] = ufoImgGetU8(tib
+ in
+ f
);
698 ufoFileStackPos
+= 1;
700 ufoInFileName
= NULL
;
705 //==========================================================================
709 //==========================================================================
710 static void ufoPopInFile (void) {
711 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
712 if (ufoInFileName
) free(ufoInFileName
);
713 if (ufoInFile
) fclose(ufoInFile
);
714 ufoFileStackPos
-= 1;
715 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
717 ufoInFileName
= stk
->fname
;
718 ufoInFileLine
= stk
->fline
;
720 // also, restore current line, because some code may need it
721 if (stk
->savedTIBSize
>= ufoTIBAreaSize
) ufoFatal("restored TIB too big");
722 if (stk
->savedTIBSize
>= sizeof(ufoCurrFileLine
)) {
723 ufoFatal("post-include restored source line is too long");
725 ufoImgPutU32(ufoAddrTIB
, 0);
726 ufoImgPutU32(ufoAddrIN
, 0);
727 if (stk
->savedTIBSize
!= 0) {
728 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
729 ufoImgPutU8(f
, stk
->savedTIB
[f
]);
730 ufoCurrFileLine
[f
] = (char)(stk
->savedTIB
[f
]&0xff);
734 ufoImgPutU8(stk
->savedTIBSize
, 0);
735 ufoCurrFileLine
[stk
->savedTIBSize
] = 0;
736 #ifdef UFO_DEBUG_INLCUDE
737 fprintf(stderr
, "INC-POP: <%s>\n", ufoCurrFileLine
);
742 //==========================================================================
746 //==========================================================================
747 static void ufoDeinit (void) {
751 if (ufoInFileName
) free(ufoInFileName
);
752 ufoInFileName
= NULL
;
755 while (ufoForthDict
!= NULL
) {
756 UForthWord
*fw
= ufoForthDict
;
757 if (fw
->buckets
!= NULL
) free(fw
->buckets
);
758 ufoForthDict
= fw
->prevAll
;
774 ufoSP
= 0; ufoRP
= 0; ufoRPTop
= 0;
775 ufoLP
= 0; ufoLBP
= 0;
776 ufoMode
= UFO_MODE_NATIVE
;
777 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
786 ufoAddrTIB
= 0; ufoAddrIN
= 0;
788 zxlblLastByte
= NULL
;
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 if (fw
== NULL
|| fw
->prevAll
!= NULL
|| fw
->hash
!= 0 || fw
->hlink
!= NULL
) abort();
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 if (fw
->pfa
== 0xffffffffU
|| FW_GET_CFAIDX(fw
) >= ufoCFAsUsed
) abort();
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 if (fw
->pfa
!= 0xffffffffU
|| FW_GET_CFAIDX(fw
) >= ufoCFAsUsed
|| fw
->buckets
!= NULL
) abort();
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 if (!UFO_VALID_VOC_FW(voc
)) abort(); // assertion
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");
1216 SourceLine
*sl
= nextUFOSrcLine();
1218 if (ufoCondStLine
>= 0) {
1219 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1221 ufoFatal("unexpected end of text");
1223 ufoInFileLine
= sl
->lineNo
;
1224 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, sl
->fname
) != 0) {
1225 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1226 ufoInFileName
= strdup(sl
->fname
);
1228 text
= (const uint8_t *)(sl
->line
!= NULL
? sl
->line
: "");
1231 size_t sslen
= strlen((const char *)text
);
1232 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1233 if (sslen
> 510) ufoFatal("input line too long");
1234 if (text
!= (const void *)ufoCurrFileLine
) {
1235 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1237 ufoCurrFileLine
[sslen
+ 0] = 10;
1238 ufoCurrFileLine
[sslen
+ 1] = 0;
1240 #ifdef UFO_DEBUG_INLCUDE
1241 fprintf(stderr
, "NEXT-LINE: <%s>\n", ufoCurrFileLine
);
1244 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1245 uint8_t ch
= text
[dpos
];
1246 // replace bad chars, because why not
1247 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1248 ufoImgPutU32(dpos
, ch
);
1250 ufoImgPutU32((uint32_t)sslen
, 10);
1251 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1255 //==========================================================================
1259 //==========================================================================
1260 static void ufoLoadMacroLine (const char *line
) {
1261 const uint8_t *text
= (const uint8_t *)line
;
1262 if (text
== NULL
) text
= (const uint8_t *)"";
1264 ufoSetTIB(0); ufoSetIN(0);
1265 SourceLine
*sl
= currSrcLine
;
1266 if (sl
== NULL
) ufoFatal("macro-wut?!");
1267 ufoInFileLine
= sl
->lineNo
;
1268 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, sl
->fname
) != 0) {
1269 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1270 ufoInFileName
= strdup(sl
->fname
);
1273 size_t sslen
= strlen((const char *)text
);
1274 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1275 if (sslen
> 510) ufoFatal("input line too long");
1276 if (sslen
!= 0) memcpy(ufoCurrFileLine
, text
, sslen
);
1277 ufoCurrFileLine
[sslen
+ 0] = 10;
1278 ufoCurrFileLine
[sslen
+ 1] = 0;
1280 for (uint32_t dpos
= 0; dpos
!= (uint32_t)sslen
; dpos
+= 1) {
1281 uint8_t ch
= text
[dpos
];
1282 // replace bad chars, because why not
1283 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1284 ufoImgPutU32(dpos
, ch
);
1286 ufoImgPutU32((uint32_t)sslen
, 10);
1287 ufoImgPutU32((uint32_t)sslen
+ 1u, 0);
1291 //==========================================================================
1295 // load next file line into TIB
1296 // return zero on success, -1 on EOF, -2 on error
1298 //==========================================================================
1299 static void ufoLoadNextLine (int crossInclude
) {
1301 case UFO_MODE_NATIVE
:
1302 ufoLoadNextLine_NativeMode(crossInclude
);
1304 case UFO_MODE_MACRO
:
1305 if (ufoCondStLine
>= 0) {
1306 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1308 ufoFatal("unexpected end of input for FORTH asm macro");
1310 default: ufoFatal("wtf?! not properly inited!");
1315 // ////////////////////////////////////////////////////////////////////////// //
1316 // working with the stacks
1317 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("UFO data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
1318 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); --ufoSP
; }
1319 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("UFO data stack underflow"); } return ufoDStack
[--ufoSP
]; }
1320 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
1321 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
1322 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
1323 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
; }
1324 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
; }
1325 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
; }
1327 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
1328 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
1329 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
); }
1330 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
; }
1332 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("UFO return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
1333 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); --ufoRP
; }
1334 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[--ufoRP
]; }
1335 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
1336 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
1337 UFO_FORCE_INLINE
void ufoROver (void) { if (ufoRP
< 2u) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-2u]); }
1338 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
; }
1339 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
; }
1340 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
; }
1342 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
1345 // ////////////////////////////////////////////////////////////////////////// //
1346 #define UFWORD(name_) \
1347 static void ufoWord_##name_ (UForthWord *self)
1349 #define UFCALL(name_) ufoWord_##name_(NULL)
1350 #define UFCFA(name_) (&ufoWord_##name_)
1354 // ////////////////////////////////////////////////////////////////////////// //
1355 static void ufoDoForth (UForthWord
*self
) {
1357 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1358 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1361 if (self
->pfastart
!= self
->pfa
) {
1363 fprintf(stderr
, "ufoDoForth: <%s>; ip=%u; pfa=%u; pfastart=%u; pfaend=%u; HERE=%u\n",
1364 self
->name
, ufoIP
, self
->pfa
, self
->pfastart
, self
->pfaend
, ufoImageUsed
);
1366 ufoPush(self
->pfastart
);
1372 //==========================================================================
1376 //==========================================================================
1377 static void ufoDoVoc (UForthWord
*self
) {
1378 ufoImgPutU32(ufoAddrContext
, self
->cfaidx
);
1382 //==========================================================================
1384 // ufoCompileWordCFA
1386 //==========================================================================
1387 UFO_FORCE_INLINE
void ufoCompileWordCFA (UForthWord
*fw
) {
1388 if (fw
== NULL
) ufoFatal("internal error in `ufoCompileWordCFA`");
1389 if (fw
->cfa
== NULL
|| FW_GET_CFAIDX(fw
) >= ufoCFAsUsed
) {
1390 ufoFatal("internal error in `ufoCompileWordCFA` (word: '%s')", fw
->name
);
1392 ufoImgEmitU32(fw
->cfaidx
);
1396 //==========================================================================
1398 // ufoCompileForthWord
1400 //==========================================================================
1401 UFO_FORCE_INLINE
void ufoCompileForthWord (const char *wname
) {
1402 ufoCompileWordCFA(ufoAlwaysWordForth(wname
));
1406 //==========================================================================
1408 // ufoCompileCompilerWord
1410 //==========================================================================
1411 UFO_FORCE_INLINE
void ufoCompileCompilerWord (const char *wname
) {
1412 ufoCompileWordCFA(ufoAlwaysWordCompiler(wname
));
1416 //==========================================================================
1418 // ufoCompileLiteral
1420 //==========================================================================
1421 static void ufoCompileLiteral (uint32_t value
) {
1422 ufoCompileCompilerWord("LIT");
1423 ufoImgEmitU32(value
);
1427 // ////////////////////////////////////////////////////////////////////////// //
1430 UFWORD(SP0_PUT
) { ufoSP
= 0; }
1434 UFWORD(RP0_PUT
) { ufoRP
= ufoRPTop
; }
1438 UFWORD(BASE
) { ufoPush(ufoBASEaddr
); }
1442 UFWORD(STATE
) { ufoPush(ufoSTATEaddr
); }
1445 // ( addr -- value32 )
1446 UFWORD(PEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)); }
1449 // ( addr -- value8 )
1450 UFWORD(CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU8(addr
)&0xffU
); }
1453 // ( addr -- value32 )
1454 UFWORD(WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)&0xffffU
); }
1457 // ( val32 addr -- )
1458 UFWORD(POKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU32(addr
, val
); }
1462 UFWORD(CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU8(addr
, val
&0xffU
); }
1465 // ( val32 addr -- )
1467 const uint32_t addr
= ufoPop();
1468 const uint32_t val
= ufoPop();
1469 ufoImgPutU32(addr
, val
&0xffffU
);
1474 // puts byte to native/zx dictionary, according to the current mode
1476 const uint32_t val
= ufoPop()&0xffU
;
1482 // puts byte to zx dictionary
1484 const uint32_t val
= ufoPop()&0xffU
;
1490 // puts uint/word to native/zx dictionary, according to the current mode
1492 const uint32_t val
= ufoPop();
1498 // puts word to zx dictionary
1500 const uint32_t val
= ufoPop();
1501 ufoZXEmitU16(val
&0xffffU
);
1505 // ( addr -- value8 )
1506 UFWORD(ZX_CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU8(addr
)); }
1510 UFWORD(ZX_CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU8(addr
, val
); }
1513 // ( addr -- value16 )
1514 UFWORD(ZX_WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU16(addr
)); }
1517 // ( val16 addr -- )
1518 UFWORD(ZX_WPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU16(addr
, val
); }
1522 UFWORD(ZX_RESERVEDQ
) {
1523 const uint32_t addr
= ufoPop();
1524 ufoPushBool(memresv
[addr
&0xffffU
]);
1529 UFWORD(ZX_RESERVEDS
) {
1530 const uint32_t addr
= ufoPop();
1531 const uint32_t flag
= ufoPop();
1532 memresv
[addr
&0xffffU
] = (flag
? 1 : 0);
1538 // is address a ZX Spectrum mmaped address?
1540 const uint32_t addr
= ufoPop();
1541 ufoPushBool(addr
&UFO_ZX_ADDR_BIT
);
1546 // convert address to ZX Spectrum mmaped address
1548 const uint32_t addr
= ufoPop();
1549 ufoPush((addr
&UFO_ZX_ADDR_MASK
)|UFO_ZX_ADDR_BIT
);
1554 // convert address to ZX Spectrum mmaped address
1556 if (ufoMode
== UFO_MODE_NATIVE
) {
1557 if (ufoIsCompiling()) {
1558 ufoCompileForthWord("(TOZX)");
1567 // convert address from ZX Spectrum mmaped address
1569 const uint32_t addr
= ufoPop();
1570 ufoPush(addr
&UFO_ZX_ADDR_MASK
);
1575 // convert address from ZX Spectrum mmaped address
1576 UFWORD(FROMZX_IMM
) {
1577 if (ufoMode
== UFO_MODE_NATIVE
) {
1578 if (ufoIsCompiling()) {
1579 ufoCompileForthWord("(FROMZX)");
1588 const uint32_t v
= ufoImgGetU32(ufoIP
++);
1594 ufoIP
= ufoImgGetU32(ufoIP
);
1597 // (TBRANCH) ( flag )
1600 ufoIP
= ufoImgGetU32(ufoIP
);
1606 // (0BRANCH) ( flag )
1609 ufoIP
= ufoImgGetU32(ufoIP
);
1616 // ( limit start -- | limit counter )
1617 // loops from start to limit-1
1624 // ( -- | limit counter )
1625 static void ufoPLoopCommon (int32_t add
) {
1626 const int32_t n
= (int32_t)ufoRPop();
1627 const int32_t lim
= (int32_t)ufoRPeek();
1628 const int32_t newn
= n
+add
;
1629 // this is how dsForth does it
1630 if ((newn
< 0 ? lim
-newn
: newn
-lim
) < 0) {
1632 ufoIP
= ufoImgGetU32(ufoIP
);
1640 // ( -- | limit counter )
1641 // loops from start to limit-1
1642 UFWORD(LOOP_PAREN
) {
1647 // ( n -- | limit counter )
1648 // loops from start to limit-1
1649 UFWORD(PLOOP_PAREN
) {
1650 const int32_t add
= (int32_t)ufoPop();
1651 ufoPLoopCommon(add
);
1658 const int32_t add = (int32_t)ufoPop();
1659 int32_t n = (int32_t)ufoRPop();
1660 const int32_t lim = (int32_t)ufoRPeek();
1661 if ((n < lim && n+add >= lim) || (n > lim && n+add <= lim)) {
1666 ufoIP = ufoImgGetU32(ufoIP);
1672 // ( counter -- | limit counter )
1674 ufoPush(ufoRPeek());
1678 // ( limit -- | limit counter )
1680 const uint32_t c
= ufoRPop();
1681 ufoPush(ufoRPeek());
1687 const uint32_t c0
= ufoRPop();
1688 const uint32_t c1
= ufoRPop();
1689 ufoPush(ufoRPeek());
1696 const uint32_t c0
= ufoRPop();
1697 const uint32_t c1
= ufoRPop();
1698 const uint32_t c2
= ufoRPop();
1699 ufoPush(ufoRPeek());
1706 //==========================================================================
1708 // ufoExecuteNativeWordInVM
1710 //==========================================================================
1711 UFO_FORCE_INLINE
void ufoExecuteNativeWordInVM (UForthWord
*fw
) {
1712 if (fw
== NULL
) abort();
1713 if (fw
->cfa
== &ufoDoForth
) {
1714 const uint32_t oldRPTop
= ufoRPTop
;
1716 fw
->cfa(fw
); // this pushes IP, and may do other work
1718 ufoRPTop
= oldRPTop
;
1725 //==========================================================================
1729 //==========================================================================
1730 UFO_FORCE_INLINE
void ufoExecCFAIdxInVM (uint32_t cfa
) {
1731 if (cfa
& UFO_RS_CFA_BIT
) {
1732 cfa
&= UFO_RS_CFA_MASK
;
1733 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1734 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1735 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1736 ufoExecuteNativeWordInVM(fw
);
1738 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1743 //==========================================================================
1747 //==========================================================================
1748 UFO_FORCE_INLINE
void ufoExecCFAIdx (uint32_t cfa
) {
1749 if (cfa
& UFO_RS_CFA_BIT
) {
1750 cfa
&= UFO_RS_CFA_MASK
;
1751 if (cfa
>= ufoCFAsUsed
) ufoFatal("calling invalid UFO word with EXECUTE (%u)", cfa
);
1752 UForthWord
*fw
= ufoForthCFAs
[cfa
];
1753 if (fw
== NULL
) ufoFatal("internal error: empty CFA index for word '%s'", fw
->name
);
1756 ufoFatal("calling invalid address with EXECUTE (%u)", cfa
);
1762 UFWORD(EXECUTE
) { ufoExecCFAIdx(ufoPop()); }
1765 UFWORD(DUP
) { ufoDup(); }
1766 // ?DUP ( n -- n n ) | ( 0 -- 0 )
1767 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
1768 // 2DUP ( n0 n1 -- n0 n1 n0 n1 ) | ( 0 -- 0 )
1769 UFWORD(DDUP
) { ufo2Dup(); }
1771 UFWORD(DROP
) { ufoDrop(); }
1773 UFWORD(DDROP
) { ufo2Drop(); }
1774 // SWAP ( n0 n1 -- n1 n0 )
1775 UFWORD(SWAP
) { ufoSwap(); }
1776 // 2SWAP ( n0 n1 -- n1 n0 )
1777 UFWORD(DSWAP
) { ufo2Swap(); }
1778 // OVER ( n0 n1 -- n0 n1 n0 )
1779 UFWORD(OVER
) { ufoOver(); }
1780 // 2OVER ( n0 n1 -- n0 n1 n0 )
1781 UFWORD(DOVER
) { ufo2Over(); }
1782 // ROT ( n0 n1 n2 -- n1 n2 n0 )
1783 UFWORD(ROT
) { ufoRot(); }
1784 // NROT ( n0 n1 n2 -- n2 n0 n1 )
1785 UFWORD(NROT
) { ufoNRot(); }
1787 // RDUP ( n -- n n )
1788 UFWORD(RDUP
) { ufoRDup(); }
1790 UFWORD(RDROP
) { ufoRDrop(); }
1791 // RSWAP ( n0 n1 -- n1 n0 )
1792 UFWORD(RSWAP
) { ufoRSwap(); }
1793 // ROVER ( n0 n1 -- n0 n1 n0 )
1794 UFWORD(ROVER
) { ufoROver(); }
1795 // RROT ( n0 n1 n2 -- n1 n2 n0 )
1796 UFWORD(RROT
) { ufoRRot(); }
1797 // RNROT ( n0 n1 n2 -- n2 n0 n1 )
1798 UFWORD(RNROT
) { ufoRNRot(); }
1801 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
1802 // R> ( -- n | n-removed )
1803 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
1804 // R@ ( -- n | n-removed )
1805 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
1809 // ( src dest count -- )
1811 uint32_t count
= ufoPop();
1812 uint32_t dest
= ufoPop();
1813 uint32_t src
= ufoPop();
1814 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1820 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? getByte(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1821 if (dest
&UFO_ZX_ADDR_BIT
) putByte(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1826 // ( src dest count -- )
1827 UFWORD(CMOVE_BACK
) {
1828 uint32_t count
= ufoPop();
1829 uint32_t dest
= ufoPop();
1830 uint32_t src
= ufoPop();
1831 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
1833 const uint32_t v
= (src
&UFO_ZX_ADDR_BIT
? getByte(src
&UFO_ZX_ADDR_MASK
) : ufoImgGetU32(src
));
1834 if (dest
&UFO_ZX_ADDR_BIT
) putByte(dest
&UFO_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufoImgPutU32(dest
, v
);
1841 // ( src dest count -- )
1843 uint32_t count
= ufoPop();
1844 uint32_t dest
= ufoPop();
1845 uint32_t src
= ufoPop();
1849 if (dest
< src
) UFCALL(CMOVE_BACK
); else UFCALL(CMOVE_FWD
);
1854 // ( addr1 count1 addr2 count2 -- flag )
1856 uint32_t count2
= ufoPop();
1857 uint32_t addr2
= ufoPop();
1858 uint32_t count1
= ufoPop();
1859 uint32_t addr1
= ufoPop();
1860 if (count2
!= count1
) { ufoPushBool(0); return; }
1862 uint8_t c0
= ufoImgGetU8(addr1
++);
1863 uint8_t c1
= ufoImgGetU8(addr2
++);
1864 if (c0
!= c1
) { ufoPushBool(0); return; }
1870 // ( addr1 count1 addr2 count2 -- flag )
1872 uint32_t count2
= ufoPop();
1873 uint32_t addr2
= ufoPop();
1874 uint32_t count1
= ufoPop();
1875 uint32_t addr1
= ufoPop();
1876 if (count2
!= count1
) { ufoPushBool(0); return; }
1878 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1879 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1880 if (c0
!= c1
) { ufoPushBool(0); return; }
1886 // ( addr1 count1 addr2 count2 -- signed-flag )
1888 uint32_t count2
= ufoPop();
1889 uint32_t addr2
= ufoPop();
1890 uint32_t count1
= ufoPop();
1891 uint32_t addr1
= ufoPop();
1892 while (count1
!= 0 && count2
!= 0) {
1893 uint8_t c0
= ufoImgGetU8(addr1
++);
1894 uint8_t c1
= ufoImgGetU8(addr2
++);
1896 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1900 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1901 else if (count2
== 0) ufoPush(1u);
1902 else __builtin_trap();
1906 // ( addr1 count1 addr2 count2 -- flag )
1908 uint32_t count2
= ufoPop();
1909 uint32_t addr2
= ufoPop();
1910 uint32_t count1
= ufoPop();
1911 uint32_t addr1
= ufoPop();
1912 while (count1
!= 0 && count2
!= 0) {
1913 uint8_t c0
= (uint8_t)(toUpper((char)ufoImgGetU8(addr1
++)));
1914 uint8_t c1
= (uint8_t)(toUpper((char)ufoImgGetU8(addr2
++)));
1916 if (c0
< c1
) ufoPush(~0u); else ufoPush(1u);
1920 if (count1
== 0) ufoPush(count2
== 0 ? 0u : ~0u);
1921 else if (count2
== 0) ufoPush(1u);
1922 else __builtin_trap();
1926 // ////////////////////////////////////////////////////////////////////////// //
1927 // text input buffer parsing
1929 //==========================================================================
1933 //==========================================================================
1934 UFO_FORCE_INLINE
uint32_t ufoTibCharAddr (void) {
1935 return ufoGetTIB() + ufoGetIN();
1939 //==========================================================================
1943 //==========================================================================
1944 UFO_FORCE_INLINE
uint8_t ufoPeekInChar (void) {
1945 return ufoImgGetU8(ufoTibCharAddr());
1949 //==========================================================================
1953 //==========================================================================
1954 UFO_FORCE_INLINE
uint8_t ufoGetInChar (void) {
1955 const uint32_t tib
= ufoGetTIB();
1956 const uint32_t in
= ufoGetIN();
1957 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1958 if (ch
!= 0) ufoSetIN(in
+ 1);
1963 //==========================================================================
1965 // ufoGetInCharAndAddr
1967 //==========================================================================
1968 UFO_FORCE_INLINE
uint8_t ufoGetInCharAndAddr (uint32_t *addr
) {
1969 const uint32_t tib
= ufoGetTIB();
1970 const uint32_t in
= ufoGetIN();
1972 const uint8_t ch
= ufoImgGetU8(tib
+ in
);
1973 if (ch
!= 0) ufoSetIN(in
+ 1);
1980 UFWORD(TIB_ADVANCE_LINE
) {
1986 UFWORD(TIB_PEEKCH
) {
1987 ufoPush(ufoPeekInChar());
1992 UFWORD(TIB_SKIPCH
) {
1993 (void)ufoGetInChar();
1999 ufoPush(ufoGetInChar());
2004 UFWORD(GET_IN_ADDR
) { ufoPush(ufoAddrIN
); }
2008 UFWORD(GET_TIB_ADDR
) { ufoPush(ufoAddrTIB
); }
2011 // ( -- size-in-cells )
2012 UFWORD(GET_TIB_SIZE
) { ufoPush(ufoTIBAreaSize
); }
2018 ufoPush(ufoImageUsed
);
2022 // ( -- n+UFO_PAD_OFFSET,aligned to 1kb )
2024 ufoPush(ufoPadAddr());
2030 uint32_t addr
= ufoPop();
2031 uint32_t len
= ufoImgGetCounter(addr
);
2037 //==========================================================================
2039 // ufoWordIsGoodDelim
2041 //==========================================================================
2042 UFO_FORCE_INLINE
int ufoWordIsGoodDelim (uint32_t ch
, uint32_t delim
) {
2043 return (ch
== delim
|| (delim
== 32 && ch
<= 32));
2048 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
2049 // does base TIB parsing; never copies anything.
2050 // as our reader is line-based, returns FALSE on EOL.
2051 // EOL is detected after skipping leading delimiters.
2052 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2053 // trailing delimiter is always skipped.
2055 const uint32_t skipLeading
= ufoPop();
2056 uint32_t delim
= ufoPop();
2057 uint32_t addr
= 0, count
;
2060 if (delim
> 255) ufoFatal("invalid delimiter char");
2063 #ifdef UFO_DEBUG_PARSE
2064 fprintf(stderr
, "*** (PARSE): delim=%u(%c); skip=%u\n", delim
, (char)delim
, skipLeading
);
2066 ch
= ufoGetInCharAndAddr(&addr
);
2067 #ifdef UFO_DEBUG_PARSE
2068 fprintf(stderr
, " FCH: %u(%c)\n", ch
, (ch
> 32 && ch
< 127 ? (char)ch
: '?'));
2070 // skip leading delimiters
2071 while (ch
!= 0 && skipLeading
&& ufoWordIsGoodDelim(ch
, delim
)) ch
= ufoGetInCharAndAddr(&addr
);
2074 #ifdef UFO_DEBUG_PARSE
2075 fprintf(stderr
, " COLLECT: %u\n", ch
);
2078 while (ch
!= 0 && !ufoWordIsGoodDelim(ch
, delim
)) { count
+= 1; ch
= ufoGetInChar(); }
2079 #ifdef UFO_DEBUG_PARSE
2080 fprintf(stderr
, " COLLECTED: ch=%u; count=%u; addr=%u\n", ch
, count
, addr
);
2086 #ifdef UFO_DEBUG_PARSE
2087 fprintf(stderr
, " EOL!\n");
2092 // skip the whole line
2093 while (ufoGetInChar() != 0) {}
2099 // ( delim skip-leading-delim? -- here TRUE / FALSE )
2100 // parse word, copy it to HERE as counted string.
2101 // adds trailing zero after the string, but doesn't include it in count.
2102 // doesn't advance line.
2103 UFWORD(PAR_WORD_OR_PARSE
) {
2106 uint32_t count
= ufoPop();
2107 uint32_t src
= ufoPop();
2109 uint32_t dest
= ufoPop();
2110 ufoImgPutU32(dest
, count
);
2111 for (uint32_t f
= 0; f
< count
; f
+= 1) {
2112 ufoImgPutU8(dest
+ f
+ 1, ufoImgGetU8(src
+ f
));
2114 ufoImgPutU32(dest
+ count
+ 1, 0); // put trailing zero, just in case
2123 // ( delim -- here )
2124 // parse word, copy it to HERE as counted string.
2125 // adds trailing zero after the string, but doesn't include it in count.
2126 // doesn't advance line.
2127 // return empty string on EOL.
2130 UFCALL(PAR_WORD_OR_PARSE
);
2133 uint32_t dest
= ufoPop();
2134 ufoImgPutU32(dest
, 0); // counter
2135 ufoImgPutU32(dest
+ 1, 0); // trailing zero
2141 // ( delim -- addr count TRUE / FALSE )
2142 // parse word w/o skipping delimiters, copy it to HERE as counted string.
2143 // adds trailing zero after the string, but doesn't include it in count.
2144 // doesn't advance line.
2145 UFWORD(PARSE_TO_HERE
) {
2147 UFCALL(PAR_WORD_OR_PARSE
);
2157 // ( -- addr count )
2158 // parse with skipping leading blanks. doesn't copy anything.
2159 // return empty string on EOL.
2160 UFWORD(PARSE_NAME
) {
2161 ufoPush(32); ufoPushBool(1);
2164 ufoPush(ufoTibCharAddr());
2170 // ( delim -- addr count TRUE / FALSE )
2171 // parse without skipping delimiters; never copies anything.
2172 // as our reader is line-based, returns FALSE on EOL.
2173 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2174 // trailing delimiter is always skipped.
2181 //==========================================================================
2183 // ufoPopStrLitToTempBuf
2185 //==========================================================================
2186 static void ufoPopStrLitToTempBuf (void) {
2187 uint32_t count
= ufoPop();
2188 uint32_t addr
= ufoPop();
2189 if (count
== 0) ufoFatal("unexpected end of line");
2190 if (count
>= (uint32_t)sizeof(ufoTempCharBuf
)) abort(); // just in case
2192 while (dpos
!= count
) {
2193 ufoTempCharBuf
[dpos
] = ufoImgGetU8(addr
+ dpos
);
2196 ufoTempCharBuf
[dpos
] = 0;
2200 //==========================================================================
2202 // ufoParseNameToTempBuf
2204 // parse forth word name from TIB, put it to `ufoTempCharBuf`.
2205 // on EOL, `ufoTempCharBuf` will be an empty string.
2207 //==========================================================================
2208 static void ufoParseNameToTempBuf (void) {
2210 if (ufoPeek() == 0) ufoFatal("word name expected");
2211 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2212 ufoPopStrLitToTempBuf();
2216 //==========================================================================
2218 // ufoParseNameToTempBufEmptyOk
2220 //==========================================================================
2221 static void ufoParseNameToTempBufEmptyOk (void) {
2223 if (ufoPeek() == 0) {
2224 ufoTempCharBuf
[0] = 0;
2226 if (ufoPeek() > UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2227 ufoPopStrLitToTempBuf();
2232 //==========================================================================
2234 // ufoPutTempStrLiteral
2236 // puts counted string literal to PAD
2237 // returns VM address of counted string
2239 //==========================================================================
2240 static uint32_t ufoPutTempStrLiteral (const char *s
) {
2242 const size_t slen
= strlen(s
);
2243 if (slen
> 1024*1024) ufoFatal("temp string too long");
2244 uint32_t dest
= ufoPadAddr();
2245 ufoImgPutU32(dest
, (uint32_t)slen
);
2246 for (size_t f
= 0; f
<= slen
; ++f
) {
2247 ufoImgPutU32(dest
+ f
+ 1, (uint8_t)(s
[f
]&0xffU
));
2253 // ////////////////////////////////////////////////////////////////////////// //
2259 uint32_t ch
= ufoPop()&0xffU
;
2260 if (ch
< 32 || ch
== 127) {
2261 if (ch
!= 10 && ch
!= 13 && ch
!= 9) { printf("?"); return; }
2263 ufoLastEmitWasCR
= (ch
== 10);
2264 if (ch
== 10) printf("\n"); else printf("%c", (char)ch
);
2270 uint32_t ch
= ufoPop()&0xffU
;
2271 printf("%c", (ch
< 32 || ch
== 127 ? '?' : (char)ch
));
2272 ufoLastEmitWasCR
= 0;
2279 ufoLastEmitWasCR
= 1;
2286 ufoLastEmitWasCR
= 0;
2292 int32_t n
= (int32_t)ufoPop();
2293 while (n
-- > 0) printf(" ");
2294 ufoLastEmitWasCR
= 0;
2300 if (!ufoLastEmitWasCR
) {
2302 ufoLastEmitWasCR
= 1;
2309 ufoPushBool(ufoLastEmitWasCR
);
2315 ufoLastEmitWasCR
= !!ufoPop();
2319 // ( addr count -- )
2321 int32_t count
= (int32_t)ufoPop();
2322 uint32_t addr
= ufoPop();
2323 while (count
-- > 0) {
2324 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2331 // ( addr count -- )
2333 int32_t count
= (int32_t)ufoPop();
2334 uint32_t addr
= ufoPop();
2335 while (count
-- > 0) {
2336 const uint8_t ch
= ufoImgGetU8(addr
++)&0xffU
;
2343 UFWORD(STRQ_PAREN
) {
2344 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2346 if (count
> 0x7fffffffU
) ufoPush(0); else ufoPush(count
);
2351 UFWORD(STRDOTQ_PAREN
) {
2352 const uint32_t count
= ufoImgGetU32(ufoIP
++);
2360 //==========================================================================
2362 // ufoNTWordAddrCount
2364 //==========================================================================
2365 static UForthWord
*ufoNTWordAddrCount (void) {
2366 uint32_t count
= ufoPop();
2367 uint32_t addr
= ufoPop();
2368 UForthWord
*fw
= ufoNFind(addr
, count
);
2370 UFCALL(SPACE
); ufoPush(addr
); ufoPush(count
); UFCALL(XTYPE
);
2371 printf(" -- wut?\n"); ufoLastEmitWasCR
= 1;
2372 ufoFatal("unknown UFO word");
2378 // ////////////////////////////////////////////////////////////////////////// //
2381 //==========================================================================
2385 //==========================================================================
2386 static char *ufoPrintNumber (uint32_t v
, int sign
) {
2387 static char buf
[64];
2388 size_t bufpos
= sizeof(buf
);
2390 int64_t n
= (sign
? (int64_t)(int32_t)v
: (int64_t)(uint32_t)v
);
2391 const char sch
= (n
< 0 ? '-' : 0);
2393 int base
= ufoImgGetU32(ufoBASEaddr
);
2394 if (base
< 2 || base
> 36) { snprintf(buf
, sizeof(buf
), "%s", "invalid-base"); return buf
; }
2396 if (bufpos
== 0) ufoFatal("number too long");
2397 char ch
= '0'+(char)(n
%base
);
2398 if (ch
> '9') ch
+= 7;
2400 } while ((n
/= base
) != 0);
2401 if (bufpos
!= 0 && sch
) buf
[--bufpos
] = sch
;
2409 int32_t v
= (int32_t)ufoPop();
2410 printf("%s ", ufoPrintNumber(v
, 1));
2416 uint32_t v
= ufoPop();
2417 printf("%s ", ufoPrintNumber(v
, 0));
2423 int32_t wdt
= (int32_t)ufoPop();
2424 int32_t v
= (int32_t)ufoPop();
2425 char *s
= ufoPrintNumber(v
, 1);
2426 int32_t slen
= (int32_t)strlen(s
);
2427 while (slen
< wdt
) { printf(" "); ++slen
; }
2434 int32_t wdt
= (int32_t)ufoPop();
2435 int32_t v
= (int32_t)ufoPop();
2436 char *s
= ufoPrintNumber(v
, 0);
2437 int32_t slen
= (int32_t)strlen(s
);
2438 while (slen
< wdt
) { printf(" "); ++slen
; }
2443 // ////////////////////////////////////////////////////////////////////////// //
2449 const uint32_t a
= ufoPop();
2456 const uint32_t b
= ufoPop();
2457 const uint32_t a
= ufoPop();
2464 const uint32_t b
= ufoPop();
2465 const uint32_t a
= ufoPop();
2472 const int32_t b
= (int32_t)ufoPop();
2473 const int32_t a
= (int32_t)ufoPop();
2474 ufoPush((uint32_t)(a
*b
));
2480 const uint32_t b
= ufoPop();
2481 const uint32_t a
= ufoPop();
2482 ufoPush((uint32_t)(a
*b
));
2488 const int32_t b
= (int32_t)ufoPop();
2489 const int32_t a
= (int32_t)ufoPop();
2490 if (b
== 0) ufoFatal("UFO division by zero");
2491 ufoPush((uint32_t)(a
/b
));
2497 const uint32_t b
= ufoPop();
2498 const uint32_t a
= ufoPop();
2499 if (b
== 0) ufoFatal("UFO division by zero");
2500 ufoPush((uint32_t)(a
/b
));
2506 const int32_t b
= (int32_t)ufoPop();
2507 const int32_t a
= (int32_t)ufoPop();
2508 if (b
== 0) ufoFatal("UFO division by zero");
2509 ufoPush((uint32_t)(a
%b
));
2515 const uint32_t b
= ufoPop();
2516 const uint32_t a
= ufoPop();
2517 if (b
== 0) ufoFatal("UFO division by zero");
2518 ufoPush((uint32_t)(a
%b
));
2522 // ( a b -- a/b, a%b )
2524 const int32_t b
= (int32_t)ufoPop();
2525 const int32_t a
= (int32_t)ufoPop();
2526 if (b
== 0) ufoFatal("UFO division by zero");
2527 ufoPush((uint32_t)(a
/b
));
2528 ufoPush((uint32_t)(a
%b
));
2532 // ( a b -- a/b, a%b )
2534 const uint32_t b
= ufoPop();
2535 const uint32_t a
= ufoPop();
2536 if (b
== 0) ufoFatal("UFO division by zero");
2537 ufoPush((uint32_t)(a
/b
));
2538 ufoPush((uint32_t)(a
%b
));
2542 // ////////////////////////////////////////////////////////////////////////// //
2548 const int32_t b
= (int32_t)ufoPop();
2549 const int32_t a
= (int32_t)ufoPop();
2556 const int32_t b
= (int32_t)ufoPop();
2557 const int32_t a
= (int32_t)ufoPop();
2564 const int32_t b
= (int32_t)ufoPop();
2565 const int32_t a
= (int32_t)ufoPop();
2566 ufoPushBool(a
<= b
);
2572 const int32_t b
= (int32_t)ufoPop();
2573 const int32_t a
= (int32_t)ufoPop();
2574 ufoPushBool(a
>= b
);
2580 const uint32_t b
= ufoPop();
2581 const uint32_t a
= ufoPop();
2588 const uint32_t b
= ufoPop();
2589 const uint32_t a
= ufoPop();
2596 const uint32_t b
= ufoPop();
2597 const uint32_t a
= ufoPop();
2598 ufoPushBool(a
<= b
);
2604 const uint32_t b
= ufoPop();
2605 const uint32_t a
= ufoPop();
2606 ufoPushBool(a
>= b
);
2612 const uint32_t b
= ufoPop();
2613 const uint32_t a
= ufoPop();
2614 ufoPushBool(a
== b
);
2620 const uint32_t b
= ufoPop();
2621 const uint32_t a
= ufoPop();
2622 ufoPushBool(a
!= b
);
2628 const uint32_t a
= ufoPop();
2635 const uint32_t a
= ufoPop();
2642 const uint32_t b
= ufoPop();
2643 const uint32_t a
= ufoPop();
2644 ufoPushBool(a
&& b
);
2650 const uint32_t b
= ufoPop();
2651 const uint32_t a
= ufoPop();
2652 ufoPushBool(a
|| b
);
2658 const uint32_t b
= ufoPop();
2659 const uint32_t a
= ufoPop();
2666 const uint32_t b
= ufoPop();
2667 const uint32_t a
= ufoPop();
2674 const uint32_t b
= ufoPop();
2675 const uint32_t a
= ufoPop();
2682 const uint32_t a
= ufoPop();
2686 UFWORD(ONEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+1u); }
2687 UFWORD(ONEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-1u); }
2688 UFWORD(TWOPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+2u); }
2689 UFWORD(TWOMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-2u); }
2690 UFWORD(THREEPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+3u); }
2691 UFWORD(THREEMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-3u); }
2692 UFWORD(FOURPLUS
) { uint32_t n
= ufoPop(); ufoPush(n
+4u); }
2693 UFWORD(FOURMINUS
) { uint32_t n
= ufoPop(); ufoPush(n
-4u); }
2694 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
*2u); }
2695 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
/2u); }
2697 UFWORD(LSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
<<c
); ufoPush(n
); }
2698 UFWORD(RSHIFT
) { uint32_t c
= ufoPop(); uint32_t n
= ufoPop(); n
= (c
> 31u ? 0u : n
>>c
); ufoPush(n
); }
2702 // ////////////////////////////////////////////////////////////////////////// //
2708 if (ufoIsCompiling()) {
2709 ufoCompileLiteral(ufoPop());
2714 // ( addr count -- addr count )
2715 UFWORD(STR_UNESCAPE
) {
2716 uint32_t count
= (int32_t)ufoPop();
2717 const uint32_t addr
= ufoPeek();
2718 const uint32_t eaddr
= addr
+ count
;
2719 uint32_t caddr
= addr
;
2720 uint32_t daddr
= addr
;
2721 while (caddr
!= eaddr
) {
2722 uint8_t ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2723 if (ch
== '\\' && caddr
!= eaddr
) {
2724 ch
= ufoImgGetU8(caddr
); caddr
+= 1;
2726 case 'r': ch
= '\r'; break;
2727 case 'n': ch
= '\n'; break;
2728 case 't': ch
= '\t'; break;
2729 case 'e': ch
= '\x1b'; break;
2730 case '`': ch
= '"'; break; // special escape to insert double-quoted
2731 case '"': ch
= '"'; break;
2732 case '\'': ch
= '\''; break;
2733 case '\\': ch
= '\\'; break;
2735 if (eaddr
- daddr
>= 1) {
2736 const int dg0
= digitInBase((char)(ufoImgGetU8(caddr
+ 1)), 16);
2737 if (dg0
< 0) ufoFatal("invalid hex string escape");
2738 if (eaddr
- daddr
>= 2) {
2739 const int dg1
= digitInBase((char)(ufoImgGetU8(caddr
+ 2)), 16);
2740 if (dg1
< 0) ufoFatal("invalid hex string escape");
2741 ch
= (uint8_t)(dg0
* 16 + dg1
);
2748 ufoFatal("invalid hex string escape");
2751 default: ufoFatal("invalid string escape");
2754 if (caddr
!= daddr
) ufoImgPutU32(daddr
, ch
);
2757 if (daddr
< eaddr
) ufoImgPutU32(daddr
, 0);
2758 ufoPush(daddr
- addr
);
2762 // I:( addr count -- addr count )
2763 // R:( -- addr count )
2764 // C:( addr count -- )
2765 // addr *MUST* be HERE+1
2766 UFWORD(STRLITERAL
) {
2767 UFCALL(STR_UNESCAPE
);
2768 if (ufoIsCompiling()) {
2769 uint32_t count
= ufoPop();
2770 uint32_t addr
= ufoPop();
2772 if (count
> 0xffffU
) ufoFatal("UFO string too long");
2773 if (addr
- 1u != ufoImageUsed
) {
2774 ufoFatal("invalid call to UFO word 'STRLITERAL'");
2776 ufoImgPutU32(addr
- 1u, count
);
2777 ufoImageUsed
+= count
+ 1u;
2783 // ( -- addr count )
2785 if (ufoIsCompiling()) ufoCompileCompilerWord("(\")");
2786 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2789 if (ufoIsInterpreting()) {
2791 uint32_t dest
= ufoPadAddr();
2792 uint32_t count
= ufoPop();
2793 uint32_t src
= ufoPop();
2794 if (dest
>= src
&& dest
<= src
+ count
) ufoFatal("something's wrong!");
2795 if (count
> 1022) ufoFatal("UFO string too long");
2796 ufoImgPutU32(dest
, count
);
2797 for (uint32_t n
= 0; n
< count
; ++n
) ufoImgPutU32(dest
+ n
+ 1, ufoImgGetU32(src
+ n
));
2798 ufoImgPutU32(dest
+ count
+ 1, 0);
2803 ufoFatal("string literal expected");
2810 if (ufoIsCompiling()) ufoCompileCompilerWord("(.\")");
2811 ufoPush(34); UFCALL(PARSE_TO_HERE
);
2814 if (ufoIsInterpreting()) {
2818 ufoFatal("string literal expected");
2823 // ////////////////////////////////////////////////////////////////////////// //
2827 //==========================================================================
2829 // ufoGetInCharAutoLineAdvance
2831 //==========================================================================
2832 static uint8_t ufoGetInCharAutoLineAdvance (void) {
2835 ch
= ufoGetInChar();
2836 if (ch
== 0) ufoLoadNextLine(0);
2843 UFWORD(COMMENTEOL
) {
2844 // just skip the whole line
2845 while (ufoGetInChar() != 0) {}
2849 UFWORD(COMMENTPAREN
) {
2851 do { ch
= ufoGetInCharAutoLineAdvance(); } while (ch
!= ')');
2854 // "(*" multiline comment
2856 uint32_t prevch
= 0, ch
= 0;
2859 ch
= ufoGetInCharAutoLineAdvance();
2860 } while (prevch
!= '*' || ch
!= ')');
2863 // "((" multiline comment
2864 UFWORD(COMMENTML_NESTED
) {
2866 uint32_t prevch
= 0, ch
= 0;
2869 ch
= ufoGetInCharAutoLineAdvance();
2870 if (prevch
== '(' && ch
== '(') { ch
= 0; level
+= 1; }
2871 else if (prevch
== ')' && ch
== ')') { ch
= 0; level
-= 1; }
2872 } while (level
!= 0);
2876 // NFIND ( addr count -- cfa TRUE | 0 )
2877 // find native/zx word
2878 // onlynativeimmflag:
2879 // 0: look for ZX word only if native word not found
2880 // !0: look for ZX word only if native word not found, or if it is not immediate
2881 // 666: prefer ZX words (used in `COMPILE`)
2882 // returned ZX CFA has `UFO_ZX_ADDR_BIT` set
2885 // look for native word
2886 // if there is none, look for zx word
2888 // look for native word
2889 // STATE == 0: (interpreting)
2890 // if there is none, look for zx word
2891 // STATE != 0: (compiling)
2892 // if no native word, or native word is not immediate, look for zx word
2894 const uint32_t count
= ufoPop();
2895 const uint32_t addr
= ufoPop();
2896 UForthWord
*fw
= ufoNFind(addr
, count
);
2898 ufoPush(fw
->cfaidx
);
2906 // convert number from addrl+1
2907 // returns address of the first inconvertible char
2908 // (XNUMBER) ( addr count -- num TRUE / FALSE )
2910 uint32_t count
= ufoPop();
2911 uint32_t addr
= ufoPop();
2914 int xbase
= (int)ufoImgGetU8(ufoBASEaddr
);
2916 // special-based numbers
2917 if (count
>= 3 && ufoImgGetU8(addr
) == '0') {
2918 switch (ufoImgGetU8(addr
+ 1)) {
2919 case 'x': case 'X': base
= 16; break;
2920 case 'o': case 'O': base
= 8; break;
2921 case 'b': case 'B': base
= 2; break;
2922 case 'd': case 'D': base
= 10; break;
2925 if (base
) { addr
+= 2; count
-= 2; }
2926 } else if (count
>= 2 && ufoImgGetU8(addr
) == '$') {
2928 addr
+= 1; count
-= 1;
2929 } else if (count
>= 2 && ufoImgGetU8(addr
) == '#') {
2931 addr
+= 1; count
-= 1;
2932 } else if (count
>= 2 && ufoImgGetU8(addr
) == '%') {
2934 addr
+= 1; count
-= 1;
2935 } else if (count
>= 3 && ufoImgGetU8(addr
) == '&') {
2936 switch (ufoImgGetU8(addr
+ 1)) {
2937 case 'h': case 'H': base
= 16; break;
2938 case 'o': case 'O': base
= 8; break;
2939 case 'b': case 'B': base
= 2; break;
2940 case 'd': case 'D': base
= 10; break;
2943 if (base
) { addr
+= 2; count
-= 2; }
2944 } else if (xbase
< 12 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'B') {
2947 } else if (xbase
< 18 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'H') {
2950 } else if (xbase
< 25 && count
> 2 && toUpper(ufoImgGetU8(addr
+ count
- 1)) == 'O') {
2957 if (!base
) base
= xbase
;
2959 if (count
== 0 || base
< 1 || base
> 36) {
2964 while (count
!= 0) {
2965 const uint32_t ch
= ufoImgGetU8(addr
);
2967 const int dig
= digitInBase((char)ch
, (int)base
);
2969 uint32_t nc
= n
* (uint32_t)base
+ (uint32_t)dig
;
2973 addr
+= 1; count
-= 1;
2990 UFCALL(PARSE_NAME
); // ( addr count )
2994 // end of input buffer; read next line
2995 #ifdef UFO_DEBUG_INLCUDE
2996 printf("*** NEW LINE ***\n");
2998 ufoLoadNextLine(1); // cross includes
3000 #ifdef UFO_DEBUG_INLCUDE
3001 printf("WORD: %u %u [", addr
, len
);
3002 ufoPush(addr
); ufoPush(len
); UFCALL(XTYPE
); printf("]"); UFCALL(CR
);
3009 // HACK: allow access to locals from code blocks
3010 // HACK: this will break badly if we'll pass such code blocks outside of the word
3011 if (len
> 1 && len
< 128 &&
3012 ufoInColon
> 0 && ufoIsCompiling() && ufoLocals
!= NULL
&&
3013 ufoImgGetU8(addr
) == ':')
3015 static char name
[257];
3017 for (uint32_t f
= 0; f
< len
; f
+= 1) name
[f
] = ufoImgGetU8(addr
+ f
);
3019 UForthLocRecord
*loc
= ufoFindLocal(name
, &wantStore
);
3022 snprintf(lwordn
, sizeof(lwordn
), "(LOCAL%c-%u)",
3023 (wantStore
? '!' : '@'), loc
->lidx
);
3024 UForthWord
*lfw
= ufoFindWordCompiler(lwordn
);
3026 ufoCompileWordCFA(lfw
);
3031 ufoCompileCompilerWord("(LOCAL!)");
3033 ufoCompileCompilerWord("(LOCAL@)");
3040 // find in dictionary
3041 ufoPush(addr
); ufoPush(len
);
3042 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3044 // word found, compile/execute
3045 UForthWord
*fw
= UFO_GET_NATIVE_CFA(ufoPop());
3046 if (!UFW_IS_IMM(fw
) && ufoIsCompiling()) {
3048 ufoCompileWordCFA(fw
);
3051 ufoExecuteNativeWordInVM(fw
);
3054 // word not found, try to parse a number
3056 if (ufoImgGetU8(addr
) == '-') { neg
= -1; ++addr
; --len
; }
3057 else if (ufoImgGetU8(addr
) == '+') { neg
= 1; ++addr
; --len
; }
3058 ufoPush(addr
); // address
3059 ufoPush(len
); // address
3061 // check if parsed successfully
3064 uint32_t n
= ufoPop();
3065 if (neg
< 0) n
= (~n
)+1u;
3069 // something wicked this way comes
3070 if (neg
) { --addr
; ++len
; }
3071 UFCALL(SPACE
); ufoPush(addr
); ufoPush(len
); UFCALL(XTYPE
);
3072 printf(" -- wut?\n"); ufoLastEmitWasCR
= 1;
3073 ufoFatal("unknown word");
3080 // ////////////////////////////////////////////////////////////////////////// //
3081 // more compiler words
3085 if (ufoIsCompiling()) ufoFatal("expecting execution mode");
3090 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3094 // ( ocond cond -- )
3096 if (ufoIsInterpreting()) ufoFatal("expecting compilation mode");
3097 const uint32_t cond
= ufoPop();
3098 const uint32_t ocond
= ufoPop();
3099 if (cond
!= ocond
) ufoFatal("unbalanced structured code");
3103 UFWORD(COMPILE_IMM
) {
3104 if (ufoIsInterpreting()) ufoFatal("cannot call `COMPILE` from interpreter");
3107 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3109 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3110 ufoCompileLiteral(cfa
);
3111 ufoCompileForthWord(",");
3113 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3114 printf(" -- wut?"); UFCALL(CR
);
3115 ufoFatal("unknown word");
3118 ufoFatal("word name expected");
3123 UFWORD(XCOMPILE_IMM
) {
3124 if (ufoIsInterpreting()) ufoFatal("cannot call `[COMPILE]` from interpreter");
3127 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3129 UForthWord
*fw
= UFO_GET_NATIVE_CFA(ufoPop());
3130 ufoCompileWordCFA(fw
);
3132 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3133 printf(" -- wut?"); UFCALL(CR
);
3134 ufoFatal("unknown word");
3137 ufoFatal("word name expected");
3145 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3147 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3148 if (ufoIsCompiling()) {
3149 ufoCompileLiteral(cfa
);
3154 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3155 printf(" -- wut?"); UFCALL(CR
);
3156 ufoFatal("unknown word");
3159 ufoFatal("word name expected");
3164 UFWORD(XTICKPFA_IMM
) {
3167 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3169 uint32_t cfa
= ufoPop();
3170 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3171 if (ufoIsCompiling()) {
3172 ufoCompileLiteral(fw
->pfa
);
3177 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3178 printf(" -- wut?"); UFCALL(CR
);
3179 ufoFatal("unknown word");
3182 ufoFatal("word name expected");
3192 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3194 uint32_t cfa
= UFO_ENSURE_NATIVE_CFA(ufoPop());
3197 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3198 printf(" -- wut?"); UFCALL(CR
);
3199 ufoFatal("unknown word");
3202 ufoFatal("word name expected");
3207 UFWORD(TICKPFA_IMM
) {
3211 UFCALL(NFIND
); // ( cfa TRUE / FALSE )
3213 uint32_t cfa
= ufoPop();
3214 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
3217 UFCALL(HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
3218 printf(" -- wut?"); UFCALL(CR
);
3219 ufoFatal("unknown word");
3222 ufoFatal("word name expected");
3230 ufoImgEmitU32(ufoPop());
3235 // calculate the forward branch offset from addr to HERE and put it into the addr
3238 const uint32_t here
= ufoPop();
3239 const uint32_t addr
= ufoPop();
3240 ufoImgPutU32(addr
, here
);
3244 // ////////////////////////////////////////////////////////////////////////// //
3247 static int ufoIsLocalsEnter (UForthWord
*ww
) {
3249 if (ww
!= NULL
&& ww
->pfa
+ 1 < ufoImageUsed
) {
3250 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3251 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3252 res
= (w
== fw
->cfaidx
);
3258 //==========================================================================
3262 //==========================================================================
3263 static uint32_t ufoPrepareEnter (UForthWord
*ww
) {
3265 if (!ufoIsCompiling()) ufoFatal("compile mode expected");
3266 if (ufoInColon
!= 1) ufoFatal("must be in a word definition");
3267 if (ww
->cfa
!= NULL
) ufoFatal("wutafuck?");
3268 if (ww
->pfa
== ufoImageUsed
) {
3269 ufoCompileCompilerWord("(L-ENTER)");
3272 UForthWord
*fw
= ufoAlwaysWordCompiler("(L-ENTER)");
3273 uint32_t w
= ufoImgGetU32(ww
->pfa
);
3274 if (w
!= fw
->cfaidx
) ufoFatal("arg/local definition must be the first word");
3275 res
= ufoImgGetU32(ww
->pfa
+ 1);
3281 //==========================================================================
3285 //==========================================================================
3286 UFO_FORCE_INLINE
void ufoUpdateEnter (UForthWord
*ww
, uint32_t val
) {
3287 ufoImgPutU32(ww
->pfa
+ 1, val
);
3294 if (ufoRP
< ufoRPTop
) ufoFatal("return stack undeflow in (EXIT)");
3295 ufoStopVM
= (ufoRP
== ufoRPTop
);
3300 UFWORD(PAR_LENTER
) {
3301 // low byte of loccount is total number of locals
3302 // higt byte is the number of args
3303 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 1;
3304 uint32_t acount
= (lcount
>> 8)&0xff;
3306 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3307 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3308 ufoFatal("out of locals stack");
3311 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3312 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3313 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3314 ufoLBP
= newbp
; ufoLP
+= lcount
;
3317 while (newbp
!= ufoLBP
) {
3318 ufoLStack
[newbp
] = ufoPop();
3324 UFWORD(PAR_LLEAVE
) {
3325 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3326 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3328 ufoLBP
= ufoLStack
[ufoLBP
];
3333 if (ufoIsInterpreting()) ufoFatal("EXIT in interpreter?");
3334 if (ufoInColon
== 1) {
3335 if (ufoColonWord
->cfa
!= NULL
) ufoFatal("invalid EXIT");
3336 if (ufoIsLocalsEnter(ufoColonWord
)) ufoCompileCompilerWord("(L-LEAVE)");
3338 ufoCompileCompilerWord("(EXIT)");
3345 ufoCompileCompilerWord("(0BRANCH)");
3348 ufoPush(UFO_QPAIRS_IF
);
3354 ufoCompileCompilerWord("(TBRANCH)");
3357 ufoPush(UFO_QPAIRS_IF
);
3363 ufoPush(UFO_QPAIRS_IF
);
3371 ufoPush(UFO_QPAIRS_IF
);
3373 ufoCompileCompilerWord("(BRANCH)");
3377 ufoPush(UFO_QPAIRS_IF
);
3379 ufoPush(UFO_QPAIRS_IF
);
3386 ufoCompileCompilerWord("(DO)");
3388 ufoPush(UFO_QPAIRS_DO
);
3394 ufoPush(UFO_QPAIRS_DO
);
3396 ufoCompileCompilerWord("(LOOP)");
3403 ufoPush(UFO_QPAIRS_DO
);
3405 ufoCompileCompilerWord("(+LOOP)");
3414 ufoPush(UFO_QPAIRS_BEGIN
);
3417 static void ufoCommonUntil (const char *bword
) {
3420 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3424 ufoPush(UFO_QPAIRS_BEGIN
);
3428 // first is begin addr
3429 ufoCompileCompilerWord(bword
);
3432 // then jumps to the end
3433 while (ufoPeek() != ~0U) { UFCALL(COMP_FWD
); }
3439 UFWORD(UNTIL
) { ufoCommonUntil("(0BRANCH)"); }
3442 UFWORD(NOT_UNTIL
) { ufoCommonUntil("(TBRANCH)"); }
3445 UFWORD(AGAIN
) { ufoCommonUntil("(BRANCH)"); }
3447 static void ufoCommonWhile (int normal
) {
3450 if (ufoPeek() == UFO_QPAIRS_WHILE
) {
3454 ufoPush(UFO_QPAIRS_BEGIN
);
3459 ufoCompileCompilerWord(normal
? "(0BRANCH)" : "(TBRANCH)");
3463 ufoPush(UFO_QPAIRS_WHILE
);
3467 UFWORD(WHILE
) { ufoCommonWhile(1); }
3470 UFWORD(NOT_WHILE
) { ufoCommonWhile(0); }
3473 //==========================================================================
3477 //==========================================================================
3478 static void ufoXOF (const char *cmpwname
, int doswap
) {
3480 ufoPush(UFO_QPAIRS_CASE
);
3482 ufoCompileForthWord("OVER");
3483 if (doswap
) ufoCompileForthWord("SWAP");
3484 ufoCompileForthWord(cmpwname
);
3485 ufoCompileCompilerWord("(0BRANCH)");
3489 ufoCompileForthWord("DROP");
3490 ufoPush(UFO_QPAIRS_OF
);
3497 ufoPush(ufoCSP
); ufoCSP
= ufoSP
; //CSP @ !CSP
3498 ufoPush(UFO_QPAIRS_CASE
);
3514 ufoPush(UFO_QPAIRS_OF
);
3516 ufoCompileCompilerWord("(BRANCH)");
3521 ufoPush(UFO_QPAIRS_IF
);
3523 ufoPush(UFO_QPAIRS_CASE
);
3529 ufoPush(UFO_QPAIRS_CASE
);
3531 ufoPush(UFO_QPAIRS_OTHER
);
3537 if (ufoPeek() != UFO_QPAIRS_OTHER
) {
3538 ufoPush(UFO_QPAIRS_CASE
);
3540 ufoCompileForthWord("DROP");
3544 //fprintf(stderr, "SP=%u; csp=%u\n", ufoSP, ufoCSP);
3545 if (ufoSP
< ufoCSP
) ufoFatal("ENDCASE compiler error");
3546 while (ufoSP
> ufoCSP
) {
3547 ufoPush(UFO_QPAIRS_IF
);
3550 ufoCSP
= ufoPop(); //CSP !
3554 // ////////////////////////////////////////////////////////////////////////// //
3555 // define Forth words
3558 //==========================================================================
3562 //==========================================================================
3563 static UForthWord
*ufoRegisterWord (const char *wname
, void (*cfa
) (UForthWord
*self
),
3566 if (!wname
) wname
= "";
3567 if (strlen(wname
) > 127) ufoFatal("too long word name '%s'", wname
);
3568 UForthWord
*fw
= ufoFindWord(wname
);
3570 if (UFW_IS_PROT(fw
)) {
3571 ufoFatal("cannot redefine protected word '%s'", wname
);
3573 printf("redefined word '%s'.\n", wname
); ufoLastEmitWasCR
= 1;
3575 fw
= calloc(1, sizeof(UForthWord
));
3576 fw
->name
= strdup(wname
);
3577 #ifdef UFO_UPPERCASE_DICT_WORDS
3578 for (char *s
= fw
->name
; *s
; ++s
) *s
= toUpper(*s
);
3581 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3583 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3584 fw
->pfastart
= ufoImageUsed
;
3586 ufoLinkWordToDict(fw
);
3587 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3588 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3589 //fprintf(stderr, "***NEW WORD #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
3594 //==========================================================================
3596 // ufoCreateNamelessForthWord
3598 //==========================================================================
3599 static UForthWord
*ufoCreateNamelessForthWord (void) {
3600 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
3601 fw
->name
= strdup("(nameless-word)");
3602 fw
->cfa
= &ufoDoForth
;
3603 FW_SET_CFAIDX(fw
, ufoCFAsUsed
);
3604 fw
->flags
= UFW_FLAG_PROTECTED
| UFW_FLAG_HIDDEN
;
3605 fw
->pfa
= 0xffffffffu
; //ufoImageUsed;
3606 fw
->pfastart
= ufoImageUsed
;
3608 ufoLinkWordToDict(fw
);
3609 if (ufoCFAsUsed
>= UFO_MAX_WORDS
) ufoFatal("too many UFO words");
3610 ufoForthCFAs
[ufoCFAsUsed
++] = fw
;
3615 //==========================================================================
3619 //==========================================================================
3620 static UForthWord
*doNativeCreate (void) {
3621 ufoParseNameToTempBuf();
3622 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3623 fw
->pfa
= ufoImageUsed
;
3624 fw
->pfastart
= ufoImageUsed
;
3631 // either native, or ZX, depending of the current mode
3633 if (ufoIsCompiling()) ufoFatal("already compiling");
3634 if (ufoInColon
!= 0) ufoFatal("invalid ':' usage");
3635 ufoWipeLocRecords();
3637 UForthWord
*fw
= doNativeCreate();
3638 fw
->cfa
= NULL
; // for now
3640 ufoSetStateCompile();
3641 //fprintf(stderr, "compiling native <%s>\n", wname);
3642 // always remember old mode
3643 ufoPush(0xdeadbeefU
); // just a flag
3648 UFWORD(VOCABULARY
) {
3649 ufoParseNameToTempBuf();
3650 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3651 fw
->pfa
= 0xffffffffU
;
3652 ufoCreateVocabData(fw
);
3655 // NESTED-VOCABULARY name
3656 UFWORD(NESTED_VOCABULARY
) {
3657 uint32_t prev
= ufoLastVoc
;
3658 UForthWord
*voc
= UFO_GET_CFAPROC(prev
);
3659 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("'NESTED_VOCABULARY' internal error");
3660 ufoParseNameToTempBuf();
3661 UForthWord
*fw
= ufoRegisterWord(ufoTempCharBuf
, NULL
, ufoDefaultVocFlags
);
3662 fw
->pfa
= 0xffffffffU
;
3663 ufoCreateVocabData(fw
);
3664 ufoLinkVocab(fw
, voc
);
3674 if (ufoVSP
== UFO_VOCSTACK_SIZE
) ufoFatal("vocabulary stack overflow");
3675 ufoVocStack
[ufoVSP
] = ufoImgGetU32(ufoAddrContext
);
3681 if (ufoVSP
== 0) ufoFatal("vocabulary stack underflow");
3683 ufoImgPutU32(ufoAddrContext
, ufoVocStack
[ufoVSP
]);
3687 UFWORD(DEFINITIONS
) {
3688 ufoImgPutU32(ufoAddrCurrent
, ufoImgGetU32(ufoAddrContext
));
3689 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3695 ufoParseNameToTempBuf();
3696 UForthWord
*fw
= ufoAlwaysWord(ufoTempCharBuf
);
3697 if (!UFO_VALID_VOC_FW(fw
)) ufoFatal("word '%s' is not a vocabulary", ufoTempCharBuf
);
3698 ufoPush(fw
->cfaidx
);
3703 UFWORD(VOC_PUBLIC_MODE
) {
3704 ufoDefaultVocFlags
&= ~UFW_FLAG_VOC_HIDDEN
;
3708 UFWORD(VOC_HIDDEN_MODE
) {
3709 ufoDefaultVocFlags
|= UFW_FLAG_VOC_HIDDEN
;
3712 // <PROTECTED-WORDS>
3713 UFWORD(VOC_PROTECTED_MODE
) {
3714 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
3717 // <UNPROTECTED-WORDS>
3718 UFWORD(VOC_UNPROTECTED_MODE
) {
3719 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
3725 if (ufoIsCompiling()) ufoFatal("already compiling");
3726 if (ufoInColon
!= 0) ufoFatal("invalid 'CREATE' usage");
3727 ufoWipeLocRecords();
3728 ufoInColon
= 0x00010000;
3729 UForthWord
*fw
= doNativeCreate();
3730 fw
->cfa
= &ufoDoVariable
; // for now
3731 //fw->flags |= UFW_FLAG_HIDDEN;
3736 UFWORD(CREATE_SEMI
) {
3737 if (ufoIsCompiling()) ufoFatal("already compiling");
3738 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'CREATE;' usage");
3739 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'CREATE;' usage");
3740 ufoLastDefinedNativeWord
= ufoColonWord
;
3741 ufoWipeLocRecords();
3743 ufoColonWord
->pfaend
= ufoImageUsed
;
3744 //ufoColonWord->flags &= ~UFW_FLAG_HIDDEN;
3749 if (ufoIsCompiling()) ufoFatal("already compiling");
3750 if (ufoInColon
!= 0x00010000) ufoFatal("invalid 'DOES>' usage");
3751 if (ufoColonWord
->cfa
!= &ufoDoVariable
) ufoFatal("invalid 'DOES>' usage");
3752 ufoColonWord
->cfa
= NULL
; // for semicolon
3753 ufoColonWord
->pfa
= ufoImageUsed
;
3754 ufoWipeLocRecords();
3756 // this is for semicolon
3758 ufoPush(0xdead0badU
); // just a flag
3759 ufoSetStateCompile();
3765 if (ufoIsInterpreting()) ufoFatal("not compiling");
3766 if (ufoInColon
!= 1) ufoFatal("where's my colon?");
3767 ufoLastDefinedNativeWord
= NULL
;
3770 const uint32_t guard
= ufoPop();
3771 if (guard
!= 0xdeadbeefU
&& guard
!= 0xdead0badU
) {
3772 ufoFatal("UFO finishing word primary magic imbalance!");
3774 // compile finishing word
3775 if (ufoColonWord
== NULL
|| ufoColonWord
->cfa
!= NULL
) ufoFatal("UFO ';' without ':'");
3776 if (ufoColonWord
->pfa
== 0xffffffffU
) abort();
3777 ufoColonWord
->cfa
= &ufoDoForth
;
3778 if (ufoIsLocalsEnter(ufoColonWord
)) {
3779 ufoCompileCompilerWord("(L-LEAVE)");
3781 ufoCompileCompilerWord("(EXIT)");
3782 //ufoDecompileForth(ufoForthDict);
3783 ufoLastDefinedNativeWord
= ufoColonWord
;
3784 ufoColonWord
->pfaend
= ufoImageUsed
;
3785 ufoSetStateInterpret();
3786 // stack must be empty
3787 //if (ufoSP) ufoFatal("UFO finishing word primary imbalance!");
3789 ufoWipeLocRecords();
3791 ufoColonWord
= NULL
;
3793 // call optimiser if there is any
3794 UForthWord
*ofw
= ufoFindWordCompiler("OPTIMISE-WORD");
3795 if (ofw
&& ofw
!= ufoLastDefinedNativeWord
) {
3796 //if (ufoMode == UFO_MODE_ZX) fprintf(stderr, "**********000: #%04X\n", disp);
3797 ufoPush(ufoLastDefinedNativeWord
->cfaidx
);
3798 ufoExecuteNativeWordInVM(ofw
);
3804 if (ufoLastDefinedNativeWord
) {
3805 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_IMMEDIATE
;
3807 ufoFatal("wtf in `IMMEDIATE`");
3812 UFWORD(PAR_PROTECTED
) {
3813 if (ufoLastDefinedNativeWord
) {
3814 // we cannot unprotect the word
3815 ufoLastDefinedNativeWord
->flags
|= UFW_FLAG_PROTECTED
;
3817 ufoFatal("wtf in `(PROTECTED)`");
3822 UFWORD(PAR_HIDDEN
) {
3823 if (ufoLastDefinedNativeWord
) {
3824 ufoLastDefinedNativeWord
->flags
^= UFW_FLAG_VOC_HIDDEN
;
3826 ufoFatal("wtf in `(HIDDEN)`");
3830 UFWORD(RECURSE_IMM
) {
3832 //if (!ufoGetState()) ufoFatal("not compiling");
3833 if (ufoLastDefinedNativeWord
) {
3834 ufoImgEmitU32(ufoLastDefinedNativeWord
->cfaidx
);
3836 ufoFatal("wtf in `RECURSE`");
3841 //==========================================================================
3843 // ufoArgsLocalsCommon
3845 //==========================================================================
3846 static void ufoArgsLocalsCommon (uint32_t increment
) {
3847 uint32_t eidx
= ufoPrepareEnter(ufoColonWord
);
3848 uint32_t ch
= ufoGetInChar();
3853 if (dpos
>= UFO_MAX_WORD_LENGTH
- 1 || dpos
>= (uint32_t)sizeof(ufoTempCharBuf
)) {
3854 ufoFatal("name too long");
3856 ufoTempCharBuf
[dpos
] = (char)ch
; dpos
+= 1;
3857 ch
= ufoGetInChar();
3859 ufoTempCharBuf
[dpos
] = 0;
3860 if ((eidx
&0xffU
) > 127) ufoFatal("too many locals at '%s'", ufoTempCharBuf
);
3862 ufoNewLocal(ufoTempCharBuf
);
3864 ch
= ufoGetInChar();
3867 ufoUpdateEnter(ufoColonWord
, eidx
);
3870 // args: name name...
3871 UFWORD(ARGS_IMM
) { ufoArgsLocalsCommon(0x0101); } // increment high byte too
3872 // locals: name name...
3873 UFWORD(LOCALS_IMM
) { ufoArgsLocalsCommon(1); }
3876 //==========================================================================
3880 //==========================================================================
3881 UFO_FORCE_INLINE
void ufoLoadLocal (uint32_t lidx
) {
3882 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
3883 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3884 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3888 //==========================================================================
3892 //==========================================================================
3893 UFO_FORCE_INLINE
void ufoStoreLocal (uint32_t lidx
) {
3894 uint32_t value
= ufoPop();
3895 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index1");
3896 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3897 ufoLStack
[ufoLBP
+ lidx
] = value
;
3903 UFWORD(LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3905 // (LOCAL@-1) .. (LOCAL@-7)
3906 UFWORD(LOCAL_LOAD_1
) { ufoLoadLocal(1); }
3907 UFWORD(LOCAL_LOAD_2
) { ufoLoadLocal(2); }
3908 UFWORD(LOCAL_LOAD_3
) { ufoLoadLocal(3); }
3909 UFWORD(LOCAL_LOAD_4
) { ufoLoadLocal(4); }
3910 UFWORD(LOCAL_LOAD_5
) { ufoLoadLocal(5); }
3911 UFWORD(LOCAL_LOAD_6
) { ufoLoadLocal(6); }
3912 UFWORD(LOCAL_LOAD_7
) { ufoLoadLocal(7); }
3913 UFWORD(LOCAL_LOAD_8
) { ufoLoadLocal(8); }
3914 UFWORD(LOCAL_LOAD_9
) { ufoLoadLocal(9); }
3915 UFWORD(LOCAL_LOAD_10
) { ufoLoadLocal(10); }
3916 UFWORD(LOCAL_LOAD_11
) { ufoLoadLocal(11); }
3917 UFWORD(LOCAL_LOAD_12
) { ufoLoadLocal(12); }
3918 UFWORD(LOCAL_LOAD_13
) { ufoLoadLocal(13); }
3919 UFWORD(LOCAL_LOAD_14
) { ufoLoadLocal(14); }
3920 UFWORD(LOCAL_LOAD_15
) { ufoLoadLocal(15); }
3921 UFWORD(LOCAL_LOAD_16
) { ufoLoadLocal(16); }
3925 UFWORD(LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3927 // (LOCAL!-1) .. (LOCAL!-7)
3928 UFWORD(LOCAL_STORE_1
) { ufoStoreLocal(1); }
3929 UFWORD(LOCAL_STORE_2
) { ufoStoreLocal(2); }
3930 UFWORD(LOCAL_STORE_3
) { ufoStoreLocal(3); }
3931 UFWORD(LOCAL_STORE_4
) { ufoStoreLocal(4); }
3932 UFWORD(LOCAL_STORE_5
) { ufoStoreLocal(5); }
3933 UFWORD(LOCAL_STORE_6
) { ufoStoreLocal(6); }
3934 UFWORD(LOCAL_STORE_7
) { ufoStoreLocal(7); }
3935 UFWORD(LOCAL_STORE_8
) { ufoStoreLocal(8); }
3936 UFWORD(LOCAL_STORE_9
) { ufoStoreLocal(9); }
3937 UFWORD(LOCAL_STORE_10
) { ufoStoreLocal(10); }
3938 UFWORD(LOCAL_STORE_11
) { ufoStoreLocal(11); }
3939 UFWORD(LOCAL_STORE_12
) { ufoStoreLocal(12); }
3940 UFWORD(LOCAL_STORE_13
) { ufoStoreLocal(13); }
3941 UFWORD(LOCAL_STORE_14
) { ufoStoreLocal(14); }
3942 UFWORD(LOCAL_STORE_15
) { ufoStoreLocal(15); }
3943 UFWORD(LOCAL_STORE_16
) { ufoStoreLocal(16); }
3946 // ////////////////////////////////////////////////////////////////////////// //
3949 // (CODEBLOCK) ( -- )
3950 UFWORD(CODEBLOCK_PAR
) {
3951 // current IP is "jump over" destination
3952 // next IP is cfaidx
3953 ufoPush(ufoImgGetU32(ufoIP
+1u)); // push cfa
3954 ufoIP
= ufoImgGetU32(ufoIP
); // branch over the code block
3957 // [: -- start code block
3958 UFWORD(CODEBLOCK_START_IMM
) {
3959 if (ufoInColon
<= 0) ufoInColon
-= 1; else ufoInColon
+= 1;
3961 ufoCompileCompilerWord("(CODEBLOCK)");
3963 ufoImgEmitU32(0); // jump over
3964 // create nameless word
3965 UForthWord
*fw
= ufoCreateNamelessForthWord();
3966 ufoImgEmitU32(fw
->cfaidx
); // cfaidx
3967 fw
->pfa
= ufoImageUsed
;
3968 fw
->pfastart
= ufoImageUsed
;
3970 ufoPush(UFO_QPAIRS_CBLOCK
);
3973 // ;] -- end code block
3974 UFWORD(CODEBLOCK_END_IMM
) {
3975 if (ufoInColon
== 0 || ufoInColon
== 1) ufoFatal("end of code block without start");
3976 if (ufoInColon
< 0) ufoInColon
+= 1; else ufoInColon
-= 1;
3977 if (!UFW_IS_HID(ufoForthDict
) || ufoForthDict
->cfa
!= &ufoDoForth
) {
3978 ufoFatal("invalid code block!");
3981 ufoPush(UFO_QPAIRS_CBLOCK
);
3983 ufoCompileCompilerWord("(EXIT)"); // finish code block
3985 ufoForthDict
->pfaend
= ufoImageUsed
;
3989 // ////////////////////////////////////////////////////////////////////////// //
3998 // ////////////////////////////////////////////////////////////////////////// //
3999 static void ufoDoVariable (UForthWord
*self
) { ufoPush(self
->pfa
); }
4000 static void ufoDoValue (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4001 static void ufoDoConst (UForthWord
*self
) { ufoPush(ufoImgGetU32(self
->pfa
)); }
4003 static void ufoDoDefer (UForthWord
*self
) {
4004 const uint32_t cfaidx
= ufoImgGetU32(self
->pfastart
);
4005 ufoExecCFAIdx(cfaidx
);
4010 UForthWord
*fvar
= doNativeCreate();
4011 fvar
->cfa
= &ufoDoValue
;
4012 fvar
->pfa
= ufoImageUsed
;
4014 ufoImgEmitU32(ufoPop());
4015 fvar
->pfaend
= ufoImageUsed
;
4019 UFWORD(VAR_NOALLOT
) {
4020 UForthWord
*fvar
= doNativeCreate();
4021 fvar
->cfa
= &ufoDoVariable
;
4022 fvar
->pfa
= ufoImageUsed
;
4023 // no variable value yet
4028 UForthWord
*fvar
= doNativeCreate();
4029 fvar
->cfa
= &ufoDoVariable
;
4030 fvar
->pfa
= ufoImageUsed
;
4032 ufoImgEmitU32(ufoPop());
4033 fvar
->pfaend
= ufoImageUsed
;
4038 UForthWord
*fvar
= doNativeCreate();
4039 fvar
->cfa
= &ufoDoConst
;
4040 fvar
->pfa
= ufoImageUsed
;
4042 ufoImgEmitU32(ufoPop());
4043 fvar
->pfaend
= ufoImageUsed
;
4048 UForthWord
*fvar
= doNativeCreate();
4049 fvar
->cfa
= &ufoDoDefer
;
4050 fvar
->pfa
= ufoImageUsed
;
4052 ufoImgEmitU32(ufoPop());
4053 fvar
->pfaend
= ufoImageUsed
;
4057 // ( size -- startaddr )
4058 // this cannot "deallot" memory
4060 uint32_t sz
= (int32_t)ufoPop();
4061 if (sz
>= 1024*1024*64) ufoFatal("cannot allot %u bytes", sz
);
4062 ufoImgEnsureSize(ufoImageUsed
+ sz
);
4063 ufoPush(ufoImageUsed
);
4075 // ( addr count -- here size )
4076 // load data file from disk, put it to HERE
4077 // file is unpacked to cells (i.e. each byte will occupy one cell)
4078 // the usual "!" and "*" modifiers are ok
4079 UFWORD(LOAD_DATA_FILE
) {
4080 ufoPopStrLitToTempBuf();
4081 const char *orgname
= ufoTempCharBuf
;
4082 int system
= 0, softinclude
= 0;
4083 while (*orgname
!= 0) {
4084 if (*orgname
== '!') {
4085 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4087 } else if (*orgname
== '?') {
4088 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4095 } while (*orgname
> 0 && *orgname
<= 32);
4097 if (*orgname
== 0) ufoFatal("empty file name");
4099 const uint32_t addr
= ufoPop();
4101 char *fname
= createIncludeName(orgname
, system
, NULL
);
4102 FILE *fl
= fopen(fname
, "rb");
4104 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4108 ssize_t res
= fread(&bt
, 1, 1, fl
);
4110 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4112 ufoImgPutU8(addr
+ count
, bt
); count
+= 1;
4121 // ZX-LOAD-DATA-FILE
4122 // ( addr count -- )
4123 // load data file from disk, put it to org, advance org
4124 // the usual "!" and "*" modifiers are ok
4125 UFWORD(ZX_LOAD_DATA_FILE
) {
4126 ufoPopStrLitToTempBuf();
4127 const char *orgname
= ufoTempCharBuf
;
4128 int system
= 0, softinclude
= 0;
4129 while (*orgname
!= 0) {
4130 if (*orgname
== '!') {
4131 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4133 } else if (*orgname
== '?') {
4134 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4141 } while (*orgname
> 0 && *orgname
<= 32);
4143 if (*orgname
== 0) ufoFatal("empty file name");
4144 char *fname
= createIncludeName(orgname
, system
, NULL
);
4145 FILE *fl
= fopen(fname
, "rb");
4147 if (!softinclude
) ufoFatal("file not found: '%s'", fname
);
4151 ssize_t res
= fread(&bt
, 1, 1, fl
);
4153 if (res
!= 1) { fclose(fl
); ufoFatal("error reading file: '%s'", fname
); }
4165 UForthWord
*fw
= ufoNTWordAddrCount();
4166 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4167 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4169 if (ufoIsCompiling()) {
4172 ufoCompileLiteral(fw
->pfa
);
4173 ufoCompileForthWord("!");
4176 ufoImgPutU32(fw
->pfa
, ufoPop());
4181 // ( value addr count -- )
4183 UForthWord
*fw
= ufoNTWordAddrCount();
4184 if (fw
->cfa
!= &ufoDoValue
&& fw
->cfa
!= &ufoDoDefer
) {
4185 ufoFatal("UFO word `%s` is not VALUE/DEFER", fw
->name
);
4187 if (ufoIsCompiling()) {
4190 ufoCompileLiteral(fw
->pfa
);
4191 ufoCompileForthWord("!");
4194 ufoImgPutU32(fw
->pfa
, ufoPop());
4201 uint32_t cfa
= ufoPop();
4202 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfa
);
4207 // ////////////////////////////////////////////////////////////////////////// //
4210 UFWORD(LSQBRACKET_IMM
) {
4211 ufoSetStateInterpret();
4215 UFWORD(RSQBRACKET
) {
4216 ufoSetStateCompile();
4220 // ////////////////////////////////////////////////////////////////////////// //
4224 // ( addr count -- flag )
4225 UFWORD(UR_HAS_LABELQ
) {
4226 ufoPopStrLitToTempBuf();
4227 ufoPushBool(urFindLabel(ufoTempCharBuf
) != NULL
);
4231 // ( addr count -- type )
4233 UFWORD(UR_GET_LABELQ_TYPE
) {
4234 ufoPopStrLitToTempBuf();
4235 UrLabelInfo
*lbl
= urFindLabel(ufoTempCharBuf
);
4236 if (lbl
== NULL
|| lbl
->type
< 0) ufoPush(0u);
4237 else ufoPush((uint32_t)lbl
->type
+ 1); // WARNING! `+1` is IMPORTANT
4241 // ( addr count -- value )
4242 // fatals when the label is not found
4243 UFWORD(UR_GET_LABELQ
) {
4244 ufoPopStrLitToTempBuf();
4245 UrLabelInfo
*lbl
= urFindLabel(ufoTempCharBuf
);
4246 if (!lbl
) ufoFatal("label '%s' not found", ufoTempCharBuf
);
4247 int32_t v
= lbl
->value
;
4248 ufoPush((uint32_t)v
);
4253 // EXECUTEs cfa, returns final res
4254 // cfa: ( addr count -- stopflag )
4255 // i.e. return non-zero from cfa to stop
4256 // res is the result of the last called cfa
4257 UFWORD(UR_FOREACH_LABEL
) {
4258 uint32_t cfaidx
= ufoPop();
4260 for (UrLabelInfo
*c
= labels
; c
; c
= c
->next
) {
4261 uint32_t addr
= ufoPutTempStrLiteral(c
->name
);
4262 uint32_t count
= ufoImgGetU32(addr
++);
4265 ufoExecCFAIdxInVM(cfaidx
);
4273 //==========================================================================
4275 // urw_set_typed_label
4277 // ( value addr count -- )
4279 //==========================================================================
4280 static void urw_set_typed_label (UForthWord
*self
, int type
) {
4281 ufoPopStrLitToTempBuf();
4282 const char *name
= ufoTempCharBuf
;
4283 int32_t val
= (int32_t)ufoPop();
4284 UrLabelInfo
*lbl
= findAddLabel(name
);
4286 if (lbl
->type
!= LBL_TYPE_UNKNOWN
&& lbl
->type
!= type
) ufoFatal("invalid label '%s' type", name
);
4287 if (type
!= LBL_TYPE_ASS
) {
4288 if (lbl
->type
>= 0 && lbl
->value
!= val
) ufoFatal("invalid label '%s' value", name
);
4292 if (lbl
->type
== LBL_TYPE_UNKNOWN
) lbl
->type
= type
;
4297 // ( value addr count -- )
4298 // create/overwrite an "assign" label
4299 UFWORD(UR_SET_LABEL_VAR
) { urw_set_typed_label(self
, LBL_TYPE_ASS
); }
4302 // ( value addr count -- )
4303 UFWORD(UR_SET_LABEL_EQU
) { urw_set_typed_label(self
, LBL_TYPE_EQU
); }
4305 // UR-SET-LABEL-CODE
4306 // ( value addr count -- )
4307 UFWORD(UR_SET_LABEL_CODE
) { urw_set_typed_label(self
, LBL_TYPE_CODE
); }
4309 // UR-SET-LABEL-STOFS
4310 // ( value addr count -- )
4311 UFWORD(UR_SET_LABEL_STOFS
) { urw_set_typed_label(self
, LBL_TYPE_STOFS
); }
4313 // UR-SET-LABEL-DATA
4314 // ( value addr count -- )
4315 UFWORD(UR_SET_LABEL_DATA
) { urw_set_typed_label(self
, LBL_TYPE_DATA
); }
4318 //==========================================================================
4320 // urw_declare_typed_label
4322 //==========================================================================
4323 static void urw_declare_typed_label (UForthWord
*self
, int type
) {
4325 ufoParseNameToTempBuf();
4326 if (ufoTempCharBuf
[0] == 0) ufoFatal("label name expected");
4327 const char *name
= ufoTempCharBuf
;
4329 UrLabelInfo
*lbl
= findAddLabel(name
);
4331 if (lbl
->type
!= LBL_TYPE_UNKNOWN
&& lbl
->type
!= type
) ufoFatal("invalid label '%s' type", name
);
4332 if (type
!= LBL_TYPE_ASS
) {
4333 if (lbl
->type
>= 0 && lbl
->value
!= val
) ufoFatal("invalid label '%s' value", name
);
4337 if (lbl
->type
== LBL_TYPE_UNKNOWN
) lbl
->type
= type
;
4340 // $LABEL-DATA: name
4341 UFWORD(DLR_LABEL_DATA_IMM
) { urw_declare_typed_label(self
, LBL_TYPE_DATA
); }
4342 // $LABEL-CODE: name
4343 UFWORD(DLR_LABEL_CODE_IMM
) { urw_declare_typed_label(self
, LBL_TYPE_CODE
); }
4360 UFWORD(UR_GETDISP
) {
4367 if (wasOrg
) ufoPush(ent
); else ufoPush(~0u);
4374 const uint32_t addr
= ufoPop();
4375 if (addr
> 0xffff) ufoFatal("invalid ORG address: %u", addr
);
4376 pc
= disp
= (uint16_t)addr
;
4378 wasOrg
= 1; // so next `ORG` will not reset it
4379 ent
= (uint16_t)addr
;
4385 // doesn't change ORG
4386 UFWORD(UR_SETDISP
) {
4387 const uint32_t addr
= ufoPop();
4388 if (addr
> 0xffff) ufoFatal("invalid DISP address: %u", addr
);
4389 disp
= (uint16_t)addr
;
4395 const uint32_t addr
= ufoPop();
4396 if (addr
> 0xffff) ufoFatal("invalid ENT address: %u", addr
);
4397 wasOrg
= 1; // so next `ORG` will not reset it
4398 ent
= (uint16_t)addr
;
4402 // ////////////////////////////////////////////////////////////////////////// //
4403 // conditional compilation
4405 typedef struct UForthCondDefine_t UForthCondDefine
;
4406 struct UForthCondDefine_t
{
4408 UForthCondDefine
*prev
;
4411 static UForthCondDefine
*ufoCondDefines
= NULL
;
4414 //==========================================================================
4416 // ufoClearCondDefines
4418 //==========================================================================
4419 static void ufoClearCondDefines (void) {
4420 while (ufoCondDefines
) {
4421 UForthCondDefine
*df
= ufoCondDefines
;
4422 ufoCondDefines
= df
->prev
;
4423 if (df
->name
) free(df
->name
);
4429 //==========================================================================
4433 //==========================================================================
4434 static int ufoHasCondDefine (const char *name
) {
4435 if (!name
|| !name
[0]) return 0;
4436 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4437 if (strcmp(dd
->name
, name
) == 0) return 1;
4443 //==========================================================================
4447 //==========================================================================
4448 static void ufoAddCondDefine (const char *name
) {
4449 if (!name
|| !name
[0]) return;
4450 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4451 if (strcmp(dd
->name
, name
) == 0) return;
4453 UForthCondDefine
*dd
= malloc(sizeof(UForthCondDefine
));
4454 dd
->name
= strdup(name
);
4455 dd
->prev
= ufoCondDefines
;
4456 ufoCondDefines
= dd
;
4460 //==========================================================================
4462 // ufoRemoveCondDefine
4464 //==========================================================================
4465 static void ufoRemoveCondDefine (const char *name
) {
4466 if (!name
|| !name
[0]) return;
4467 UForthCondDefine
*pp
= NULL
;
4468 for (UForthCondDefine
*dd
= ufoCondDefines
; dd
; dd
= dd
->prev
) {
4469 if (strcmp(dd
->name
, name
) == 0) {
4470 if (pp
) pp
->prev
= dd
->prev
; else ufoCondDefines
= dd
->prev
;
4480 //==========================================================================
4482 // ufoParseConditionTerm
4484 //==========================================================================
4485 static int ufoParseConditionTerm (int doskip
) {
4487 if (strEquCI(ufoTempCharBuf
, "DEFINED")) {
4488 ufoParseNameToTempBuf();
4489 res
= (doskip
? 0 : ufoHasCondDefine(ufoTempCharBuf
));
4490 } else if (strEquCI(ufoTempCharBuf
, "UNDEFINED")) {
4491 ufoParseNameToTempBuf();
4492 res
= (doskip
? 0 : !ufoHasCondDefine(ufoTempCharBuf
));
4493 } else if (strEquCI(ufoTempCharBuf
, "HAS-WORD")) {
4494 ufoParseNameToTempBuf();
4495 res
= (doskip
? 0 : !!ufoFindWord(ufoTempCharBuf
));
4496 } else if (strEquCI(ufoTempCharBuf
, "NO-WORD")) {
4497 ufoParseNameToTempBuf();
4498 res
= (doskip
? 0 : !ufoFindWord(ufoTempCharBuf
));
4499 } else if (strEquCI(ufoTempCharBuf
, "HAS-LABEL")) {
4500 ufoParseNameToTempBuf();
4501 res
= (doskip
? 0 : !!urFindLabel(ufoTempCharBuf
));
4502 } else if (strEquCI(ufoTempCharBuf
, "NO-LABEL")) {
4503 ufoParseNameToTempBuf();
4504 res
= (doskip
? 0 : !urFindLabel(ufoTempCharBuf
));
4505 } else if (strEquCI(ufoTempCharBuf
, "PASS0")) {
4506 res
= (doskip
? 0 : (pass
== 0));
4507 } else if (strEquCI(ufoTempCharBuf
, "PASS1")) {
4508 res
= (doskip
? 0 : (pass
== 1));
4514 UrLabelInfo
*lbl
= urFindLabel(ufoTempCharBuf
);
4520 res
= !!strtol(ufoTempCharBuf
, &e
, 10);
4521 if (*e
) ufoFatal("undefined label '%s'", ufoTempCharBuf
);
4525 ufoParseNameToTempBufEmptyOk();
4530 //==========================================================================
4532 // ufoParseConditionUnary
4534 //==========================================================================
4535 static int ufoParseConditionUnary (int doskip
) {
4537 if (strEquCI(ufoTempCharBuf
, "(")) {
4538 res
= ufoParseConditionExpr(doskip
);
4539 if (!strEquCI(ufoTempCharBuf
, ")")) ufoFatal("unbalanced parens in $IF condition");
4540 } else if (strEquCI(ufoTempCharBuf
, "NOT")) {
4541 ufoParseNameToTempBuf();
4542 res
= !ufoParseConditionUnary(doskip
);
4544 res
= ufoParseConditionTerm(doskip
);
4550 //==========================================================================
4552 // ufoParseConditionAnd
4554 //==========================================================================
4555 static int ufoParseConditionAnd (int doskip
) {
4556 int res
= ufoParseConditionUnary(doskip
);
4557 doskip
= (res
== 0);
4558 while (strEquCI(ufoTempCharBuf
, "AND") || strEquCI(ufoTempCharBuf
, "&&")) {
4559 ufoParseNameToTempBuf();
4560 int r2
= ufoParseConditionUnary(doskip
);
4563 doskip
= (res
== 0);
4570 //==========================================================================
4572 // ufoParseConditionOr
4574 //==========================================================================
4575 static int ufoParseConditionOr (int doskip
) {
4576 int res
= ufoParseConditionAnd(doskip
);
4577 doskip
= (res
!= 0);
4578 while (strEquCI(ufoTempCharBuf
, "OR") || strEquCI(ufoTempCharBuf
, "||")) {
4579 ufoParseNameToTempBuf();
4580 int r2
= ufoParseConditionAnd(doskip
);
4583 doskip
= (res
!= 0);
4590 //==========================================================================
4592 // ufoParseConditionExpr
4594 //==========================================================================
4595 static int ufoParseConditionExpr (int doskip
) {
4596 return ufoParseConditionOr(doskip
);
4600 //==========================================================================
4602 // ufoSkipConditionals
4604 //==========================================================================
4605 static void ufoSkipConditionals (int toelse
) {
4606 const int oldCondStLine
= ufoCondStLine
;
4607 ufoCondStLine
= ufoInFileLine
;
4608 int iflevel
= 0, done
= 0;
4611 ufoParseNameToTempBufEmptyOk();
4612 if (ufoTempCharBuf
[0]) {
4613 // nested conditionals
4614 if (strEquCI(ufoTempCharBuf
, "$IF")) {
4616 } else if (strEquCI(ufoTempCharBuf
, "$ENDIF")) {
4617 // in nested ifs, look only for $ENDIF
4621 // it doesn't matter which part we're skipping, it ends here anyway
4624 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELSE")) {
4625 // if we're skipping "true" part, go on
4629 // we're skipping "false" part, there should be no else
4630 ufoFatal("unexpected $ELSE, skipping from line %d", ufoCondStLine
);
4633 } else if (iflevel
== 0 && strEquCI(ufoTempCharBuf
, "$ELIF")) {
4634 // if we're skipping "true" part, go on
4636 // process the conditional
4637 int res
= ufoParseConditionExpr(0);
4638 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4639 // either resume normal execution, or keep searching for $ELSE
4645 // we're skipping "false" part, there should be no else
4646 ufoFatal("unexpected $ELIFxx, skipping from line %d", ufoCondStLine
);
4650 } while (done
== 0);
4651 if (iflevel
!= 0) abort(); // assertion
4653 ufoCondStLine
= oldCondStLine
;
4657 //==========================================================================
4659 // ufoProcessConditional
4661 //==========================================================================
4662 static void ufoProcessConditional (void) {
4663 ufoParseNameToTempBuf();
4664 int res
= ufoParseConditionExpr(0);
4665 if (ufoTempCharBuf
[0]) ufoFatal("invalid $IF condition");
4667 ufoSkipConditionals(1); // skip to $ELSE
4675 // ( count addr -- )
4676 UFWORD(ASM_WARNING
) {
4677 ufoPopStrLitToTempBuf();
4678 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4679 fprintf(stdout
, "*** USER WARNING ");
4680 if (ufoInFile
!= NULL
) {
4681 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4682 } else if (currSrcLine
!= NULL
) {
4683 fprintf(stdout
, "at file %s, line %d: ", currSrcLine
->fname
, currSrcLine
->lineNo
);
4685 fprintf(stdout
, "somewhere in time: ");
4687 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4692 // ( count addr -- )
4694 ufoPopStrLitToTempBuf();
4695 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4696 fprintf(stdout
, "*** USER ERROR ");
4697 if (ufoInFile
!= NULL
) {
4698 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
4699 } else if (currSrcLine
!= NULL
) {
4700 fprintf(stdout
, "at file %s, line %d: ", currSrcLine
->fname
, currSrcLine
->lineNo
);
4702 fprintf(stdout
, "somewhere in time: ");
4704 fprintf(stdout
, "%s\n", ufoTempCharBuf
);
4710 UFWORD(DLR_DEFINE
) {
4711 ufoParseNameToTempBuf();
4712 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4713 ufoAddCondDefine(ufoTempCharBuf
);
4718 ufoParseNameToTempBuf();
4719 if (ufoTempCharBuf
[0] == 0) ufoFatal("name expected");
4720 ufoRemoveCondDefine(ufoTempCharBuf
);
4723 // these words can be encoundered only when we're done with some $IF, so skip to $ENDIF
4725 UFWORD(DLR_ELSE_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELSE without $IF"); ufoSkipConditionals(0); }
4727 UFWORD(DLR_ELIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ELIF without $IF"); --ufoInCondIf
; ufoSkipConditionals(0); }
4729 UFWORD(DLR_ENDIF_IMM
) { if (!ufoInCondIf
) ufoFatal("$ENDIF without $IF"); --ufoInCondIf
; }
4732 UFWORD(DLR_IF_IMM
) { ufoProcessConditional(); }
4736 // ( addr count -- )
4739 uint32_t count
= ufoPop();
4740 uint32_t addr
= ufoPop();
4742 int system
= 0, softinclude
= 0;
4745 while (count
!= 0) {
4746 ch
= ufoImgGetU8(addr
);
4748 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4750 } else if (ch
== '?') {
4751 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4757 addr
+= 1; count
-= 1;
4758 ch
= ufoImgGetU8(addr
);
4759 } while (ch
<= 32 && count
!= 0);
4763 if ((size_t)count
>= sizeof(fname
)) ufoFatal("include file name too long");
4765 while (count
!= 0) {
4766 fname
[dpos
] = (char)ufoImgGetU8(addr
); dpos
+= 1;
4767 addr
+= 1; count
-= 1;
4771 char *ffn
= ufoCreateIncludeName(fname
, system
);
4772 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4774 if (softinclude
) { free(ffn
); return; }
4775 ufoFatal("INCLUDE: file '%s' not found", ffn
);
4780 ufoInFileName
= ffn
;
4782 // trigger next line loading
4783 ufoSetTIB(0); ufoSetIN(0);
4788 //==========================================================================
4790 // ufoDollarIncludeCommon
4792 //==========================================================================
4793 static void ufoDollarIncludeCommon (const char *defname
) {
4796 int system
= 0, softinclude
= 0;
4798 int skipit
= (defname
!= NULL
&& ufoHasCondDefine(defname
));
4800 ch
= ufoGetInChar();
4801 while (ch
!= 0 && ch
!= '"' && ch
!= '<') {
4802 ch
= ufoGetInChar();
4805 if (ch
== 0) ufoFatal("quoted file name expected");
4807 if (ch
== '<') { system
= 1; qch
= '>'; } else qch
= '"';
4808 ch
= ufoGetInChar();
4810 if (ch
== 0) ufoFatal("properly quoted file name expected");
4812 if (system
) ufoFatal("invalid file name (duplicate system mark)");
4814 } else if (ch
== '?') {
4815 if (softinclude
) ufoFatal("invalid file name (duplicate soft mark)");
4821 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
!= qch
);
4826 while (ch
!= 0 && ch
!= qch
) {
4827 if ((size_t)dpos
>= sizeof(fname
)) ufoFatal("include file name too long");
4828 fname
[dpos
] = (char)ch
; dpos
+= 1;
4829 ch
= ufoGetInChar();
4832 // final parsing checks
4833 if (ch
== 0) ufoFatal("properly quoted file name expected");
4834 ch
= ufoGetInChar();
4836 do { ch
= ufoGetInChar(); } while (ch
!= 0 && ch
<= 32);
4837 if (ch
!= 0) ufoFatal("unexpected extra text");
4840 if (defname
!= NULL
) ufoAddCondDefine(defname
);
4841 char *ffn
= ufoCreateIncludeName(fname
, system
);
4842 FILE *fl
= ufoOpenFileOrDir(&ffn
);
4844 if (softinclude
) { free(ffn
); return; }
4845 ufoFatal("$INCLUDE: file '%s' not found", ffn
);
4850 ufoInFileName
= ffn
;
4853 // trigger next line loading
4854 ufoSetTIB(0); ufoSetIN(0);
4859 // $INCLUDE-ONCE define-guard filename
4860 UFWORD(DLR_INCLUDE_ONCE
) {
4861 ufoParseNameToTempBuf();
4862 ufoDollarIncludeCommon(ufoTempCharBuf
);
4865 // $INCLUDE filename
4866 UFWORD(DLR_INCLUDE
) {
4867 ufoDollarIncludeCommon(NULL
);
4873 UFWORD(DUMP_STACK
) {
4874 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4875 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
4876 for (uint32_t sp
= 0; sp
< ufoSP
; ++sp
) {
4877 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
4885 //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]);
4886 ufoPopStrLitToTempBuf();
4887 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
4888 ufoFatal("%s", ufoTempCharBuf
);
4892 // ////////////////////////////////////////////////////////////////////////// //
4896 //==========================================================================
4898 // ufoSetForthOnlyDefs
4900 //==========================================================================
4901 static void ufoSetForthOnlyDefs (void) {
4902 ufoImgPutU32(ufoAddrCurrent
, ufoForthVocCFA
);
4903 ufoImgPutU32(ufoAddrContext
, ufoForthVocCFA
);
4907 //==========================================================================
4909 // ufoCreateVocSetOnlyDefs
4911 //==========================================================================
4912 static UForthWord
*ufoCreateVocSetOnlyDefs (const char *wname
, UForthWord
*parentvoc
) {
4913 UForthWord
*fw
= ufoRegisterWord(wname
, NULL
, ufoDefaultVocFlags
);
4914 fw
->pfa
= 0xffffffffU
;
4915 ufoCreateVocabData(fw
);
4917 ufoLinkVocab(fw
, parentvoc
);
4918 // and set as active
4919 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
4920 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
4925 //==========================================================================
4927 // ufoVocSetOnlyDefs
4929 //==========================================================================
4930 __attribute__((unused
)) static void ufoVocSetOnlyDefs (UForthWord
*fw
) {
4931 if (UFO_VALID_VOC_FW(fw
)) {
4932 ufoImgPutU32(ufoAddrCurrent
, fw
->cfaidx
);
4933 ufoImgPutU32(ufoAddrContext
, fw
->cfaidx
);
4935 ufoSetForthOnlyDefs();
4940 //==========================================================================
4944 //==========================================================================
4945 static void ufoDefine (const char *wname
) {
4946 UForthWord
*fw
= ufoRegisterWord(wname
, &ufoDoForth
, ufoDefaultVocFlags
);
4947 fw
->pfa
= ufoImageUsed
;
4948 fw
->pfastart
= ufoImageUsed
;
4950 //fprintf(stderr, "***DEFINING #%u: <%s> at 0x%08x\n", ufoCFAsUsed-1u, ufoForthCFAs[ufoCFAsUsed-1u]->name, fw->pfa);
4951 ufoSetStateCompile();
4955 //==========================================================================
4959 //==========================================================================
4960 static void ufoDefineDone (void) {
4961 ufoLastDefinedNativeWord
= NULL
;
4963 if (ufoSP
) ufoFatal("UFO finishing word primary imbalance!");
4964 //if (!ufoForthDict || ufoForthDict->cfa) ufoFatal("UFO ';' without ':'");
4965 if (ufoForthDict
->pfa
== 0xffffffffU
) abort();
4966 ufoForthDict
->cfa
= &ufoDoForth
;
4967 ufoForthDict
->pfaend
= ufoImageUsed
;
4968 ufoCompileCompilerWord("(EXIT)");
4969 //ufoDecompileForth(ufoForthDict);
4970 ufoLastDefinedNativeWord
= ufoForthDict
;
4971 ufoSetStateInterpret();
4975 //==========================================================================
4979 //==========================================================================
4980 static void ufoNumber (uint32_t v
) {
4981 ufoCompileCompilerWord("LIT");
4986 //==========================================================================
4990 //==========================================================================
4991 static void ufoCompile (const char *wname
) {
4992 UForthWord
*fw
= ufoFindWord(wname
);
4996 long v
= strtol(wname
, &end
, 0);
4997 if (end
== wname
|| *end
) ufoFatal("UFO word '%s' not found", wname
);
4998 ufoNumber((uint32_t)v
);
5000 // compile/execute a word
5001 if (UFW_IS_IMM(fw
)) {
5002 ufoExecuteNativeWordInVM(fw
);
5004 ufoCompileWordCFA(fw
);
5010 //==========================================================================
5014 //==========================================================================
5015 static __attribute__((unused
)) void ufoString (const char *str
) {
5016 ufoCompileCompilerWord("(\")");
5018 size_t slen
= strlen(str
);
5019 if (slen
> 65535) ufoFatal("UFO string too long");
5020 ufoImgEmitU32((uint32_t)slen
);
5022 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5028 //==========================================================================
5032 //==========================================================================
5033 static __attribute__((unused
)) void ufoDotString (const char *str
) {
5034 ufoCompileCompilerWord("(.\")");
5036 size_t slen
= strlen(str
);
5037 if (slen
> 65535) ufoFatal("UFO string too long");
5038 ufoImgEmitU32((uint32_t)slen
);
5040 ufoImgEmitU32((uint32_t)(str
[0]&0xffU
));
5046 // ////////////////////////////////////////////////////////////////////////// //
5048 #include "urforth_dbg.c"
5052 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5054 ufoFatal("there is no UFO debug breakpoint support in windoze");
5056 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
5059 fprintf(stderr
, "WARNING: cannot start UFO debug session, because standard streams are not on TTY!\n");
5065 // ////////////////////////////////////////////////////////////////////////// //
5069 // ( vocid -- cfa / 0 )
5070 UFWORD(WORDS_ITER_NEW
) {
5071 uint32_t vocid
= ufoPop();
5072 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5073 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("WORDS-ITER-NEW expects a valid vocid");
5074 UForthWord
*fw
= voc
->latest
;
5075 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5076 uint32_t cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5081 // ( cfa -- cfa / 0 )
5082 // closes iterator on completion
5083 UFWORD(WORDS_ITER_PREV
) {
5084 uint32_t cfa
= ufoPop();
5085 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5086 if (fw
!= NULL
) fw
= fw
->prevVoc
;
5087 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5088 cfa
= (fw
!= NULL
? fw
->cfaidx
: 0);
5093 // ( cfa -- addr count )
5094 // somewhere at PAD; invalid CFA returns empty string
5095 UFWORD(WORDS_ITER_NAME
) {
5096 uint32_t cfa
= ufoPop();
5097 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5098 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5099 uint32_t addr
= ufoPutTempStrLiteral(fw
->name
);
5100 uint32_t count
= ufoImgGetU32(addr
++);
5104 uint32_t dest
= ufoPadAddr();
5105 ufoImgPutU32(dest
, 0);
5106 ufoImgPutU32(dest
+1, 0);
5108 ufoPush(0u); // count
5113 // ( cfa -- pfa / 0 )
5114 UFWORD(WORDS_ITER_PFA
) {
5115 uint32_t cfa
= ufoPop();
5116 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5117 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5126 UFWORD(WORDS_ITER_IMMQ
) {
5127 uint32_t cfa
= ufoPop();
5128 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5129 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5130 ufoPushBool(UFW_IS_IMM(fw
));
5138 UFWORD(WORDS_ITER_PROTQ
) {
5139 uint32_t cfa
= ufoPop();
5140 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5141 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5142 ufoPushBool(UFW_IS_PROT(fw
));
5148 // WORDS-ITER-HIDDEN?
5150 UFWORD(WORDS_ITER_HIDDENQ
) {
5151 uint32_t cfa
= ufoPop();
5152 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5153 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5154 ufoPushBool(UFW_IS_VOC_HID(fw
));
5171 UFWORD(WORDS_ITER_TYPEQ
) {
5172 uint32_t cfa
= ufoPop();
5173 UForthWord
*fw
= UFO_GET_CFAPROC(cfa
);
5174 if (fw
!= NULL
&& fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5175 if (fw
->cfa
== &ufoDoForth
) ufoPush(fw
->pfa
== fw
->pfastart
? 2 : 7);
5176 else if (fw
->cfa
== &ufoDoVariable
) ufoPush(3);
5177 else if (fw
->cfa
== &ufoDoValue
) ufoPush(4);
5178 else if (fw
->cfa
== &ufoDoConst
) ufoPush(5);
5179 else if (fw
->cfa
== &ufoDoDefer
) ufoPush(6);
5180 else if (fw
->cfa
== &ufoDoVoc
) ufoPush(7);
5181 else ufoPush(1); // code
5189 // ( vocid cfa -- res )
5190 // EXECUTEs cfa, returns final res
5191 // cfa: ( wordcfa -- stopflag )
5192 // i.e. return non-zero from cfa to stop
5193 // res is the result of the last called cfa
5194 UFWORD(UFO_FOREACH_WORD
) {
5195 uint32_t cfaidx
= ufoPop();
5196 uint32_t vocid
= ufoPop();
5198 UForthWord
*fw
= NULL
;
5199 UForthWord
*voc
= UFO_GET_CFAPROC(vocid
);
5200 if (!UFO_VALID_VOC_FW(voc
)) ufoFatal("FOREACH-WORD expects a valid vocid");
5202 while (fw
!= NULL
&& (fw
->cfa
== NULL
|| UFW_IS_HID(fw
))) fw
= fw
->prevVoc
;
5205 while (res
== 0 && fw
!= NULL
) {
5206 if (fw
->cfa
!= NULL
&& !UFW_IS_HID(fw
)) {
5207 ufoPush(fw
->cfaidx
);
5208 ufoExecCFAIdxInVM(cfaidx
);
5218 // ////////////////////////////////////////////////////////////////////////// //
5222 UFWORD(DLR_END_FORTH
) {
5223 if (ufoMode
!= UFO_MODE_NATIVE
) ufoFatal("$END_FORTH in non-native mode");
5224 if (ufoIsCompiling()) ufoFatal("$END_FORTH: still compiling something");
5225 longjmp(ufoInlineQuitJP
, 1);
5229 //==========================================================================
5231 // ufoDecompileForth
5233 //==========================================================================
5234 static void ufoDecompileForthPart (uint32_t addr
, uint32_t endaddr
, int indent
) {
5235 while (addr
!= 0 && addr
< ufoImageUsed
&& addr
< endaddr
) {
5236 uint32_t cfaidx
= ufoImgGetU32(addr
);
5237 fprintf(stderr
, "%8u: ", addr
);
5238 for (int f
= 0; f
< indent
; f
+= 1) fputc(' ', stderr
);
5239 if ((cfaidx
& UFO_RS_CFA_BIT
) == 0) {
5240 fprintf(stderr
, "<bad-cfa>");
5243 cfaidx
&= UFO_RS_CFA_MASK
;
5244 if (cfaidx
>= ufoCFAsUsed
) {
5245 fprintf(stderr
, "<bad-cfa>");
5248 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
5249 fprintf(stderr
, "%s", fw
->name
);
5251 if (fw
->cfa
== UFCFA(BRANCH
) ||
5252 fw
->cfa
== UFCFA(0BRANCH
) ||
5253 fw
->cfa
== UFCFA(TBRANCH
) ||
5254 fw
->cfa
== UFCFA(LOOP_PAREN
) ||
5255 fw
->cfa
== UFCFA(PLOOP_PAREN
))
5257 uint32_t jaddr
= ufoImgGetU32(addr
++);
5258 fprintf(stderr
, " %u", jaddr
);
5259 } else if (fw
->cfa
== UFCFA(LIT
) || fw
->cfa
== UFCFA(PAR_LENTER
)) {
5260 uint32_t n
= ufoImgGetU32(addr
++);
5261 fprintf(stderr
, " %u", n
);
5262 } else if (fw
->cfa
== UFCFA(STRQ_PAREN
) || fw
->cfa
== UFCFA(STRDOTQ_PAREN
)) {
5263 uint32_t count
= ufoImgGetU32(addr
++);
5264 fprintf(stderr
, " cnt=%u; ~", count
);
5266 uint8_t ch
= ufoImgGetU32(addr
++)&0xffU
;
5267 if (ch
== '\r') fprintf(stderr
, "\\r");
5268 else if (ch
== '\n') fprintf(stderr
, "\\n");
5269 else if (ch
== '\t') fprintf(stderr
, "\\t");
5270 else if (ch
== '\\') fprintf(stderr
, "\\\\");
5271 else if (ch
== '"') fprintf(stderr
, "\\`");
5272 else if (ch
< 32 || ch
== 127) fprintf(stderr
, "\\x%02x", ch
);
5273 else fprintf(stderr
, "%c", (char)ch
);
5275 fprintf(stderr
, "~");
5276 } else if (fw
->cfa
== UFCFA(CODEBLOCK_PAR
)) {
5277 uint32_t jover
= ufoImgGetU32(addr
++);
5278 addr
+= 1; // skip cfa idx
5279 fputc('\n', stderr
);
5280 ufoDecompileForthPart(addr
, jover
, indent
+ 2);
5286 fputc('\n', stderr
);
5291 //==========================================================================
5293 // ufoDecompileForth
5295 //==========================================================================
5296 static void ufoDecompileForth (UForthWord
*fw
) {
5298 fprintf(stderr
, "====: %s", fw
->name
);
5299 if (fw
->cfa
== &ufoDoForth
) {
5300 if (fw
->pfa
!= fw
->pfastart
) {
5301 fprintf(stderr
, " -- DOES, data at %d", fw
->pfastart
);
5303 fputc('\n', stderr
);
5304 ufoDecompileForthPart(fw
->pfa
, fw
->pfaend
, 0);
5305 } else if (fw
->cfa
== ufoDoDefer
) {
5306 fprintf(stderr
, " -- DEFER\n");
5307 } else if (fw
->cfa
== ufoDoConst
) {
5308 fprintf(stderr
, " -- CONSTANT\n");
5309 } else if (fw
->cfa
== ufoDoValue
) {
5310 fprintf(stderr
, " -- VALUE\n");
5311 } else if (fw
->cfa
== ufoDoVariable
) {
5312 fprintf(stderr
, " -- VARIABLE\n");
5314 fprintf(stderr
, "----\n");
5318 // ( addr count -- )
5319 UFWORD(UFO_DECOMPILE_INTERNAL
) {
5320 UForthWord
*fw
= ufoNTWordAddrCount();
5321 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
5322 ufoDecompileForth(fw
);
5325 // (UFO-BUCKET-STATS)
5327 UFWORD(PAR_UFO_BUCKET_STATS) {
5328 if (!ufoLastEmitWasCR) { printf("\n"); ufoLastEmitWasCR = 1; }
5329 int used = 0, min = 0x7fffffff, max = -1;
5330 for (unsigned f = 0; f < UFO_DICT_HASH_BUCKETS; f += 1) {
5331 UForthWord *fw = ufoForthDictBuckets[f];
5335 while (fw != NULL) { total += 1; fw = fw->hlink; }
5336 if (total < min) min = total;
5337 if (total > max) max = total;
5340 printf("BUCKETS USED: %d\n", used);
5342 printf("MIN BUCKET: %d\n", min);
5343 printf("MAX BUCKET: %d\n", max);
5349 // ////////////////////////////////////////////////////////////////////////// //
5352 #define UFWORD(name_) ufoRegisterWord(""#name_, ufoWord_##name_, ufoDefaultVocFlags)
5353 #define UFWORDX(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, ufoDefaultVocFlags)
5355 #define UFWORD_IMM(name_) ufoRegisterWord(""#name_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5356 #define UFWORDX_IMM(strname_,name_) ufoRegisterWord(strname_, ufoWord_##name_, UFW_FLAG_IMMEDIATE | ufoDefaultVocFlags)
5359 #define UFC(wn_) ufoCompile(""#wn_);
5360 #define UFS(wn_) ufoString(""#wn_);
5361 #define UFDS(wn_) ufoDotString(""#wn_);
5362 #define UFN(wn_) ufoNumber(wn_);
5364 #define UFBEGIN UFCALL(BEGIN);
5365 #define UFAGAIN UFCALL(AGAIN);
5368 //==========================================================================
5372 //==========================================================================
5373 static void ufoDefineQuit (void) {
5374 ufoDefine("UFO-RUN-LOOP");
5383 //==========================================================================
5385 // ufoDefineConstant
5387 //==========================================================================
5388 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5389 UForthWord
*fw
= ufoRegisterWord(name
, &ufoDoConst
, ufoDefaultVocFlags
);
5390 fw
->pfa
= ufoImageUsed
;
5391 fw
->pfastart
= ufoImageUsed
;
5393 ufoImgEmitU32(value
);
5394 fw
->pfaend
= ufoImageUsed
;
5398 //==========================================================================
5402 //==========================================================================
5403 static void ufoDefineMisc (void) {
5404 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
5410 ufoNumber(16); UFC(BASE
); UFC(!);
5413 ufoDefine("DECIMAL");
5414 ufoNumber(10); UFC(BASE
); UFC(!);
5418 UFC(0) UFC(SWAP
) UFC(!)
5422 UFC(1) UFC(SWAP
) UFC(!)
5426 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(+) UFC(SWAP
) UFC(!)
5430 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(SWAP
) UFC(-) UFC(SWAP
) UFC(!)
5434 UFC(DUP
) UFC(@
) UFC(1+) UFC(SWAP
) UFC(!)
5438 UFC(DUP
) UFC(@
) UFC(2+) UFC(SWAP
) UFC(!)
5442 UFC(DUP
) UFC(@
) UFC(3+) UFC(SWAP
) UFC(!)
5446 UFC(DUP
) UFC(@
) UFC(4+) UFC(SWAP
) UFC(!)
5450 UFC(DUP
) UFC(@
) UFC(1-) UFC(SWAP
) UFC(!)
5454 UFC(DUP
) UFC(@
) UFC(2-) UFC(SWAP
) UFC(!)
5458 UFC(DUP
) UFC(@
) UFC(3-) UFC(SWAP
) UFC(!)
5462 UFC(DUP
) UFC(@
) UFC(4-) UFC(SWAP
) UFC(!)
5466 ufoNumber(0); UFC(=);
5470 ufoNumber(0); UFC(<>);
5474 ufoNumber(0); UFC(!=);
5478 ufoNumber(0); UFC(<);
5482 ufoNumber(0); UFC(>);
5486 ufoNumber(0); UFC(<=);
5490 ufoNumber(0); UFC(>=);
5494 ufoNumber(0); UFC(U
>);
5498 ufoNumber(1); UFC(=);
5502 ufoNumber(1); UFC(<>);
5506 ufoNumber(1); UFC(!=);
5510 ufoNumber(1); UFC(<);
5514 ufoNumber(1); UFC(>);
5518 ufoNumber(1); UFC(<=);
5522 ufoNumber(1); UFC(>=);
5526 ufoNumber(1); UFC(U
>);
5530 ufoNumber(1); UFC(U
<=);
5533 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
5537 //==========================================================================
5541 //==========================================================================
5542 static void ufoReset (void) {
5543 ufoWipeLocRecords();
5548 ufoSP
= 0; ufoRP
= 0;
5549 ufoLP
= 0; ufoLBP
= 0;
5553 ufoSetStateInterpret();
5555 ufoSetTIB(0); ufoSetIN(0);
5558 ufoColonWord
= NULL
;
5560 ufoDefaultVocFlags
= 0;
5562 ufoSetForthOnlyDefs();
5566 //==========================================================================
5570 //==========================================================================
5571 static void ufoInitCommon (void) {
5572 ufoForthDict
= NULL
;
5573 ufoColonWord
= NULL
;
5574 ufoLastVoc
= ~0U; ufoDefaultVocFlags
= 0;
5575 ufoVSP
= 0; ufoForthVocCFA
= 0; ufoCompSuppVocCFA
= 0; ufoMacroVocCFA
= 0;
5577 ufoDStack
= calloc(UFO_DSTACK_SIZE
, sizeof(ufoDStack
[0]));
5578 ufoRStack
= calloc(UFO_RSTACK_SIZE
, sizeof(ufoRStack
[0]));
5579 ufoLStack
= calloc(UFO_LSTACK_SIZE
, sizeof(ufoLStack
[0]));
5580 ufoForthCFAs
= calloc(UFO_MAX_WORDS
, sizeof(ufoForthCFAs
[0]));
5581 // CFA 0 is reserved for FORTH vocabulary
5585 while (ufoImageUsed
<= ufoTIBAreaSize
) ufoImgEmitU32(0);
5588 ufoBASEaddr
= ufoImageUsed
;
5592 ufoSTATEaddr
= ufoImageUsed
;
5596 ufoAddrTIB
= ufoImageUsed
;
5600 ufoAddrIN
= ufoImageUsed
;
5604 ufoAddrContext
= ufoImageUsed
;
5608 ufoAddrCurrent
= ufoImageUsed
;
5611 ufoSetStateInterpret();
5613 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
5614 fw
->name
= strdup("FORTH");
5616 FW_SET_CFAIDX(fw
, 0); // known thing
5617 fw
->flags
= UFW_FLAG_PROTECTED
;
5618 fw
->pfa
= 0xffffffffU
;
5619 ufoForthVocCFA
= fw
->cfaidx
;
5620 ufoForthCFAs
[0] = fw
; // for proper links
5621 ufoCreateVocabData(fw
);
5622 // set CURRENT and CONTEXT
5623 ufoSetForthOnlyDefs();
5625 ufoLinkWordToDict(fw
);
5627 ufoDefaultVocFlags
= UFW_FLAG_PROTECTED
;
5629 UForthWord
*vcomp
= ufoCreateVocSetOnlyDefs("COMPILER", NULL
);
5630 ufoCompSuppVocCFA
= vcomp
->cfaidx
;
5631 ufoSetForthOnlyDefs();
5633 ufoMacroVocCFA
= ufoCreateVocSetOnlyDefs("URASM-MACROS", NULL
)->cfaidx
;
5634 ufoSetForthOnlyDefs();
5636 UForthWord
*vstr
= ufoCreateVocSetOnlyDefs("STRING", NULL
);
5637 ufoSetForthOnlyDefs();
5640 // base low-level interpreter words
5641 ufoDefineConstant("FALSE", 0);
5642 ufoDefineConstant("TRUE", ufoTrueValue
);
5644 ufoDefineConstant("BL", 32);
5645 ufoDefineConstant("NL", 10);
5647 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
5648 UFWORDX("SP0!", SP0_PUT
);
5649 UFWORDX("RP0!", RP0_PUT
);
5654 UFWORDX("C@", CPEEK
);
5655 UFWORDX("C!", CPOKE
);
5656 UFWORDX("W@", WPEEK
);
5657 UFWORDX("W!", WPOKE
);
5658 UFWORDX("C,", CCOMMA
);
5659 UFWORDX(",", COMMA
);
5661 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
5662 ufoVocSetOnlyDefs(vcomp
);
5664 UFWORDX("(BRANCH)", BRANCH
);
5665 UFWORDX("(TBRANCH)", TBRANCH
);
5666 UFWORDX("(0BRANCH)", 0BRANCH
);
5667 UFWORDX("(DO)", DO_PAREN
);
5668 UFWORDX("(LOOP)", LOOP_PAREN
);
5669 UFWORDX("(+LOOP)", PLOOP_PAREN
);
5671 // low-level compiler words
5672 UFWORDX("STRLITERAL", STRLITERAL
);
5674 UFWORDX("(\")", STRQ_PAREN
);
5675 UFWORDX("(.\")", STRDOTQ_PAREN
);
5677 UFWORDX("(EXIT)", PAR_EXIT
);
5678 UFWORDX("(L-ENTER)", PAR_LENTER
);
5679 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
5681 UFWORDX("?EXEC", QEXEC
);
5682 UFWORDX("?COMP", QCOMP
);
5683 UFWORDX("?PAIRS", QPAIRS
);
5684 UFWORDX("COMP-BACK", COMP_BACK
);
5685 UFWORDX("COMP-FWD", COMP_FWD
);
5687 UFWORDX("(LOCAL@)", LOCAL_LOAD
);
5688 UFWORDX("(LOCAL!)", LOCAL_STORE
);
5690 UFWORDX("(LOCAL@-1)", LOCAL_LOAD_1
);
5691 UFWORDX("(LOCAL@-2)", LOCAL_LOAD_2
);
5692 UFWORDX("(LOCAL@-3)", LOCAL_LOAD_3
);
5693 UFWORDX("(LOCAL@-4)", LOCAL_LOAD_4
);
5694 UFWORDX("(LOCAL@-5)", LOCAL_LOAD_5
);
5695 UFWORDX("(LOCAL@-6)", LOCAL_LOAD_6
);
5696 UFWORDX("(LOCAL@-7)", LOCAL_LOAD_7
);
5697 UFWORDX("(LOCAL@-8)", LOCAL_LOAD_8
);
5698 UFWORDX("(LOCAL@-9)", LOCAL_LOAD_9
);
5699 UFWORDX("(LOCAL@-10)", LOCAL_LOAD_10
);
5700 UFWORDX("(LOCAL@-11)", LOCAL_LOAD_11
);
5701 UFWORDX("(LOCAL@-12)", LOCAL_LOAD_12
);
5702 UFWORDX("(LOCAL@-13)", LOCAL_LOAD_13
);
5703 UFWORDX("(LOCAL@-14)", LOCAL_LOAD_14
);
5704 UFWORDX("(LOCAL@-15)", LOCAL_LOAD_15
);
5705 UFWORDX("(LOCAL@-16)", LOCAL_LOAD_16
);
5707 UFWORDX("(LOCAL!-1)", LOCAL_STORE_1
);
5708 UFWORDX("(LOCAL!-2)", LOCAL_STORE_2
);
5709 UFWORDX("(LOCAL!-3)", LOCAL_STORE_3
);
5710 UFWORDX("(LOCAL!-4)", LOCAL_STORE_4
);
5711 UFWORDX("(LOCAL!-5)", LOCAL_STORE_5
);
5712 UFWORDX("(LOCAL!-6)", LOCAL_STORE_6
);
5713 UFWORDX("(LOCAL!-7)", LOCAL_STORE_7
);
5714 UFWORDX("(LOCAL!-8)", LOCAL_STORE_8
);
5715 UFWORDX("(LOCAL!-9)", LOCAL_STORE_9
);
5716 UFWORDX("(LOCAL!-10)", LOCAL_STORE_10
);
5717 UFWORDX("(LOCAL!-11)", LOCAL_STORE_11
);
5718 UFWORDX("(LOCAL!-12)", LOCAL_STORE_12
);
5719 UFWORDX("(LOCAL!-13)", LOCAL_STORE_13
);
5720 UFWORDX("(LOCAL!-14)", LOCAL_STORE_14
);
5721 UFWORDX("(LOCAL!-15)", LOCAL_STORE_15
);
5722 UFWORDX("(LOCAL!-16)", LOCAL_STORE_16
);
5724 UFWORDX("(CODEBLOCK)", CODEBLOCK_PAR
);
5725 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
5726 ufoSetForthOnlyDefs();
5729 UFWORDX_IMM("RECURSE", RECURSE_IMM
);
5733 UFWORDX("?DUP", QDUP
);
5734 UFWORDX("2DUP", DDUP
);
5736 UFWORDX("2DROP", DDROP
);
5738 UFWORDX("2SWAP", DSWAP
);
5740 UFWORDX("2OVER", DOVER
);
5751 UFWORDX(">R", DTOR
);
5752 UFWORDX("R>", RTOD
);
5753 UFWORDX("R@", RPEEK
);
5755 UFWORDX("CMOVE>", CMOVE_FWD
);
5756 UFWORDX("CMOVE", CMOVE_BACK
);
5757 UFWORDX("MOVE", MOVE
);
5759 ufoVocSetOnlyDefs(vstr
);
5760 UFWORDX("=", STREQU
);
5761 UFWORDX("=CI", STREQUCI
);
5762 UFWORDX("CMP", STRCMP
);
5763 UFWORDX("CMP-CI", STRCMPCI
);
5764 UFWORDX("UNESCAPE", STR_UNESCAPE
);
5765 ufoSetForthOnlyDefs();
5767 // some useful words
5768 UFWORDX_IMM("(", COMMENTPAREN
);
5769 UFWORDX_IMM("\\", COMMENTEOL
);
5770 UFWORDX_IMM(";;", COMMENTEOL
);
5771 UFWORDX_IMM("(*", COMMENTML
);
5772 UFWORDX_IMM("((", COMMENTML_NESTED
);
5783 UFWORDX("LASTCR?", LASTCRQ
);
5784 UFWORDX("LASTCR!", LASTCRSET
);
5788 UFWORDX("U.", UDOT
);
5789 UFWORDX(".R", DOTR
);
5790 UFWORDX("U.R", UDOTR
);
5795 UFWORDX("-", MINUS
);
5797 UFWORDX("U*", UMUL
);
5799 UFWORDX("U/", UDIV
);
5800 UFWORDX("MOD", MOD
);
5801 UFWORDX("UMOD", UMOD
);
5802 UFWORDX("/MOD", DIVMOD
);
5803 UFWORDX("U/MOD", UDIVMOD
);
5807 UFWORDX(">", GREAT
);
5808 UFWORDX("<=", LESSEQU
);
5809 UFWORDX(">=", GREATEQU
);
5810 UFWORDX("U<", ULESS
);
5811 UFWORDX("U>", UGREAT
);
5812 UFWORDX("U<=", ULESSEQU
);
5813 UFWORDX("U>=", UGREATEQU
);
5815 UFWORDX("<>", NOTEQU
);
5816 UFWORDX("!=", NOTEQU
);
5821 UFWORDX("LOGAND", LOGAND
);
5823 UFWORDX("LOGOR", LOGOR
);
5826 UFWORDX("1+", ONEPLUS
);
5827 UFWORDX("1-", ONEMINUS
);
5828 UFWORDX("2+", TWOPLUS
);
5829 UFWORDX("2-", TWOMINUS
);
5830 UFWORDX("3+", THREEPLUS
);
5831 UFWORDX("3-", THREEMINUS
);
5832 UFWORDX("4+", FOURPLUS
);
5833 UFWORDX("4-", FOURMINUS
);
5834 UFWORDX("2U*", ONESHL
);
5835 UFWORDX("2U/", ONESHR
);
5840 UFWORDX_IMM("\"", STRQ
);
5841 UFWORDX_IMM(".\"", STRDOTQ
);
5843 UFWORDX("LITERAL", LITERAL
);
5844 UFWORDX_IMM("COMPILE", COMPILE_IMM
);
5845 UFWORDX_IMM("[COMPILE]", XCOMPILE_IMM
);
5846 UFWORDX_IMM("[']", XTICK_IMM
);
5847 UFWORDX_IMM("['PFA]", XTICKPFA_IMM
);
5849 UFWORDX_IMM("'", TICK_IMM
);
5850 UFWORDX_IMM("'PFA", TICKPFA_IMM
);
5852 UFWORDX_IMM("EXIT", EXIT_IMM
);
5858 UFWORDX_IMM("THEN", ENDIF
);
5862 UFWORDX_IMM("NOT-WHILE", NOT_WHILE
);
5863 UFWORDX_IMM("REPEAT", AGAIN
);
5865 UFWORDX_IMM("NOT-UNTIL", NOT_UNTIL
);
5867 UFWORD_IMM(ENDCASE
);
5869 UFWORDX_IMM("&OF", AND_OF
);
5871 UFWORD_IMM(OTHERWISE
);
5874 UFWORDX_IMM("+LOOP", PLOOP
);
5877 UFWORDX("I'", ITICK
);
5878 UFWORDX("J'", JTICK
);
5880 UFWORDX(":", COLON
);
5881 UFWORDX_IMM(";", SEMI
);
5883 UFWORDX("CREATE;", CREATE_SEMI
);
5884 UFWORDX("DOES>", DOES
);
5887 UFWORDX_IMM("VOCID:", VOCID_IMM
);
5891 UFWORD(DEFINITIONS
);
5892 UFWORDX("NESTED-VOCABULARY", NESTED_VOCABULARY
);
5893 UFWORDX("<PUBLIC-WORDS>", VOC_PUBLIC_MODE
);
5894 UFWORDX("<HIDDEN-WORDS>", VOC_HIDDEN_MODE
);
5895 UFWORDX("<PROTECTED-WORDS>", VOC_PROTECTED_MODE
);
5896 UFWORDX("<UNPROTECTED-WORDS>", VOC_UNPROTECTED_MODE
);
5898 UFWORDX("(PROTECTED)", PAR_PROTECTED
);
5899 UFWORDX("(HIDDEN)", PAR_HIDDEN
);
5901 UFWORDX_IMM("LOCALS:", LOCALS_IMM
);
5902 UFWORDX_IMM("ARGS:", ARGS_IMM
);
5905 UFWORDX("(PARSE)", PAR_PARSE
);
5906 UFWORDX("(WORD-OR-PARSE)", PAR_WORD_OR_PARSE
);
5908 UFWORDX("PARSE-TO-HERE", PARSE_TO_HERE
);
5909 UFWORDX("PARSE-NAME", PARSE_NAME
);
5910 UFWORDX("PARSE", PARSE
);
5912 UFWORDX("TIB-ADVANCE-LINE", TIB_ADVANCE_LINE
);
5913 UFWORDX("TIB-CHAR?", TIB_PEEKCH
);
5914 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
5915 UFWORDX("TIB-GETCH", TIB_GETCH
);
5916 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
5918 UFWORDX(">IN", GET_IN_ADDR
);
5919 UFWORDX("TIB", GET_TIB_ADDR
);
5920 UFWORDX("TIB-SIZE", GET_TIB_SIZE
);
5924 UFWORDX("(NUMBER)", XNUMBER
);
5927 UFWORDX("VALUE", VALUE
);
5928 UFWORDX("VAR-NOALLOT", VAR_NOALLOT
);
5929 UFWORDX("VARIABLE", VARIABLE
);
5930 UFWORDX("CONSTANT", CONSTANT
);
5931 UFWORDX("DEFER", DEFER
);
5932 UFWORDX("LOAD-DATA-FILE", LOAD_DATA_FILE
);
5933 UFWORDX("N-ALLOT", N_ALLOT
);
5934 UFWORDX("ALLOT", ALLOT
);
5935 UFWORDX("HERE", HERE
);
5936 UFWORDX("PAD", PAD
);
5937 UFWORDX_IMM("TO", TO_IMM
);
5938 UFWORDX("NAMED-TO", NAMED_TO
);
5939 UFWORDX("CFA->PFA", CFA2PFA
);
5941 UFWORDX_IMM("[", LSQBRACKET_IMM
);
5942 UFWORDX("]", RSQBRACKET
);
5944 UFWORDX_IMM("[:", CODEBLOCK_START_IMM
);
5945 UFWORDX_IMM(";]", CODEBLOCK_END_IMM
);
5946 /* code blocks are used like this:
5947 : A [: ( addr count -- res ) TYPE 0 ;] ASM-FOREACH-LABEL DROP ;
5948 i.e. it creates inlined code block, and returns its CFA.
5953 (void)ufoCreateVocSetOnlyDefs("URASM", NULL
);
5954 // UrAsm label types
5955 // WARNING! keep in sync with C source!
5956 ufoDefineConstant("LBL-TYPE-UNKNOWN", 0);
5957 ufoDefineConstant("LBL-TYPE-ASS", LBL_TYPE_ASS
+ 1);
5958 ufoDefineConstant("LBL-TYPE-EQU", LBL_TYPE_EQU
+ 1);
5959 ufoDefineConstant("LBL-TYPE-CODE", LBL_TYPE_CODE
+ 1);
5960 ufoDefineConstant("LBL-TYPE-STOFS", LBL_TYPE_STOFS
+ 1);
5961 ufoDefineConstant("LBL-TYPE-DATA", LBL_TYPE_DATA
+ 1);
5963 UFWORDX("C,", ZX_CCOMMA
);
5964 UFWORDX("W,", ZX_WCOMMA
);
5965 UFWORDX("C@", ZX_CPEEK
);
5966 UFWORDX("C!", ZX_CPOKE
);
5967 UFWORDX("W@", ZX_WPEEK
);
5968 UFWORDX("W!", ZX_WPOKE
);
5970 UFWORDX("RESERVED?", ZX_RESERVEDQ
);
5971 UFWORDX("RESERVED!", ZX_RESERVEDS
);
5973 UFWORDX("HAS-LABEL?", UR_HAS_LABELQ
);
5974 UFWORDX("LABEL-TYPE?", UR_GET_LABELQ_TYPE
);
5975 UFWORDX("GET-LABEL", UR_GET_LABELQ
);
5976 UFWORDX("FOREACH-LABEL", UR_FOREACH_LABEL
);
5977 UFWORDX("SET-LABEL-VAR", UR_SET_LABEL_VAR
);
5978 UFWORDX("SET-LABEL-EQU", UR_SET_LABEL_EQU
);
5979 UFWORDX("SET-LABEL-CODE", UR_SET_LABEL_CODE
);
5980 UFWORDX("SET-LABEL-STOFS", UR_SET_LABEL_STOFS
);
5981 UFWORDX("SET-LABEL-DATA", UR_SET_LABEL_DATA
);
5982 UFWORDX("PASS@", UR_PASSQ
);
5984 UFWORDX("LOAD-DATA-FILE", ZX_LOAD_DATA_FILE
);
5986 UFWORDX("ORG@", UR_GETORG
);
5987 UFWORDX("DISP@", UR_GETDISP
);
5988 UFWORDX("ENT@", UR_GETENT
);
5989 UFWORDX("ORG!", UR_SETORG
);
5990 UFWORDX("DISP!", UR_SETDISP
);
5991 UFWORDX("ENT!", UR_SETENT
);
5993 UFWORDX("WARNING", ASM_WARNING
);
5994 UFWORDX("ERROR", ASM_ERROR
);
5995 ufoSetForthOnlyDefs();
5998 // conditional compilation
5999 UFWORDX_IMM("$IF", DLR_IF_IMM
);
6000 UFWORDX_IMM("$ELSE", DLR_ELSE_IMM
);
6001 UFWORDX_IMM("$ELIF", DLR_ELIF_IMM
);
6002 UFWORDX_IMM("$ENDIF", DLR_ENDIF_IMM
);
6004 UFWORDX_IMM("$DEFINE", DLR_DEFINE
);
6005 UFWORDX_IMM("$UNDEF", DLR_UNDEF
);
6007 UFWORDX_IMM("$LABEL-DATA:", DLR_LABEL_DATA_IMM
);
6008 UFWORDX_IMM("$LABEL-CODE:", DLR_LABEL_CODE_IMM
);
6010 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE
);
6011 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE
);
6013 UFWORDX("INCLUDE", INCLUDE
);
6016 (void)ufoCreateVocSetOnlyDefs("UFO", NULL
);
6017 UFWORDX("FATAL", UFO_FATAL
);
6019 // UrForth internal word types
6020 ufoDefineConstant("WTYPE-NONE", 0);
6021 ufoDefineConstant("WTYPE-CODE", 1);
6022 ufoDefineConstant("WTYPE-FORTH", 2);
6023 ufoDefineConstant("WTYPE-VARIABLE", 3);
6024 ufoDefineConstant("WTYPE-VALUE", 4);
6025 ufoDefineConstant("WTYPE-CONSTANT", 5);
6026 ufoDefineConstant("WTYPE-DEFER", 6);
6027 ufoDefineConstant("WTYPE-DOES", 7);
6028 ufoDefineConstant("WTYPE-VOCABULARY", 8);
6030 UFWORDX("WORDS-ITER-NEW", WORDS_ITER_NEW
);
6031 UFWORDX("WORDS-ITER-PREV", WORDS_ITER_PREV
);
6032 UFWORDX("WORDS-ITER-NAME", WORDS_ITER_NAME
);
6033 UFWORDX("WORDS-ITER-PFA", WORDS_ITER_PFA
);
6034 UFWORDX("WORDS-ITER-IMM?", WORDS_ITER_IMMQ
);
6035 UFWORDX("WORDS-ITER-PROT?", WORDS_ITER_PROTQ
);
6036 UFWORDX("WORDS-ITER-HIDDEN?", WORDS_ITER_HIDDENQ
);
6037 UFWORDX("WORDS-ITER-TYPE?", WORDS_ITER_TYPEQ
);
6038 UFWORDX("FOREACH-WORD", UFO_FOREACH_WORD
);
6040 UFWORDX("<MODE@>", UFO_MODER
);
6042 ufoSetForthOnlyDefs();
6045 (void)ufoCreateVocSetOnlyDefs("DEBUG", NULL
);
6046 UFWORDX("DUMP-STACK", DUMP_STACK
);
6047 //ufoDefaultVocFlags |= UFW_FLAG_VOC_HIDDEN;
6048 UFWORDX("DECOMPILE", UFO_DECOMPILE_INTERNAL
);
6049 UFWORDX("BP", UFO_BP
);
6050 //ufoDefaultVocFlags &= ~UFW_FLAG_VOC_HIDDEN;
6051 ufoSetForthOnlyDefs();
6057 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6060 ufoDefaultVocFlags
|= UFW_FLAG_PROTECTED
;
6062 UFWORDX_IMM("$END_FORTH", DLR_END_FORTH
);
6063 UFWORDX_IMM("$END-FORTH", DLR_END_FORTH
);
6064 //UFWORDX("$END-FORTH", DLR_END_FORTH_NOIMM);
6067 UFWORDX("ZXADDR?", ZXADDRQ
);
6068 UFWORDX("(TOZX)", TOZX
);
6069 UFWORDX_IMM("TOZX", TOZX_IMM
);
6070 UFWORDX("(FROMZX)", FROMZX
);
6071 UFWORDX_IMM("FROMZX", FROMZX_IMM
);
6075 ufoDefaultVocFlags
&= ~UFW_FLAG_PROTECTED
;
6079 //==========================================================================
6083 // address interpreter
6085 //==========================================================================
6086 static void ufoRunVM (void) {
6088 while (!ufoStopVM
) {
6089 uint32_t cfaidx
= ufoImgGetU32(ufoIP
++);
6090 if (cfaidx
& UFO_RS_CFA_BIT
) {
6091 cfaidx
&= UFO_RS_CFA_MASK
;
6092 if (cfaidx
>= ufoCFAsUsed
) {
6093 ufoFatal("UFO tried to execute an unknown word: 0x%08x (max is 0x%08x); IP=0x%08x", cfaidx
, ufoCFAsUsed
, ufoIP
-1);
6095 UForthWord
*fw
= ufoForthCFAs
[cfaidx
];
6096 if (fw
== NULL
) ufoFatal("VM internal error: empty CFA");
6099 ufoFatal("VM tried to execute something that is not a word");
6106 //==========================================================================
6110 //==========================================================================
6111 static void ufoRunIt (const char *wname
) {
6112 UForthWord
*fw
= ufoAlwaysWord(wname
);
6113 if (fw
->cfa
!= &ufoDoForth
) {
6114 ufoFatal("UFO '%s' word is not a Forth word", wname
);
6116 ufoExecuteNativeWordInVM(fw
);
6120 //==========================================================================
6124 //==========================================================================
6125 void ufoInlineInit (void) {
6126 ufoMode
= UFO_MODE_NATIVE
;
6127 zxlblLastByte
= NULL
;
6128 ufoTrueValue
= ~0u; // -1 is better!
6132 ufoSetStateInterpret();
6134 ufoInFileLine
= 0; ufoCondStLine
= -1;
6135 ufoInFileName
= NULL
;
6141 char *ufmname
= ufoCreateIncludeName("init", 1);
6142 FILE *ufl
= ufoOpenFileOrDir(&ufmname
);
6145 ufoInFileName
= ufmname
;
6153 //==========================================================================
6157 //==========================================================================
6158 static void ufoInlineRun (void) {
6159 if (ufoMode
== UFO_MODE_NONE
) {
6162 ufoMode
= UFO_MODE_NATIVE
;
6164 if (setjmp(ufoInlineQuitJP
) == 0) {
6166 //UFCALL(INTERPRET);
6167 ufoRunIt("UFO-RUN-LOOP");
6168 abort(); // the thing that should not be
6170 while (ufoFileStackPos
!= 0) ufoPopInFile();
6175 //==========================================================================
6179 //==========================================================================
6180 static uint32_t ufoIsMacro (const char *wname
) {
6181 if (ufoMode
!= UFO_MODE_NONE
) {
6182 UForthWord
*fw
= ufoFindWordMacro(wname
);
6183 if (fw
!= NULL
&& fw
->cfa
== &ufoDoForth
) return fw
->cfaidx
;
6189 //==========================================================================
6193 //==========================================================================
6194 static void ufoMacroRun (uint32_t cfaidx
, const char *line
) {
6195 if (ufoMode
== UFO_MODE_NONE
) abort();
6196 UForthWord
*fw
= UFO_GET_NATIVE_CFA(cfaidx
);
6197 ufoMode
= UFO_MODE_MACRO
;
6198 if (fw
->cfa
!= &ufoDoForth
) {
6199 ufoFatal("UFO '%s' macro word is not a Forth word", fw
->name
);
6202 if (setjmp(ufoInlineQuitJP
) == 0) {
6204 ufoLoadMacroLine(line
);
6205 ufoExecuteNativeWordInVM(fw
);
6206 while (ufoFileStackPos
!= 0) ufoPopInFile();
6208 while (ufoFileStackPos
!= 0) ufoPopInFile();
6209 ufoFatal("wtf with UFO macro?!");