I'm trying to implement a kind of "conditional
:" in ATLAST, the reasoning being I have a file that gets
FLOADed multiple times to handle multiple steps of my program flow (I'm essentially abusing Forth as an assembler, step 1 does a first parsing for references, etc. and in step 2 the instruction words actually emit bytes).
So when declaring words for "macros" in that file, it errors out in step 2, because they were already declared in step 1, but I also can't just
FORGET them, because that would forget everything that came afterwards, such as the references I just collected in step 1.
So essentially I need a "
: that only runs in step 1", my idea being something like this:
VARIABLE STAGE : :: STAGE @ 0 = IF [COMPILE] : ( be a word declaration ) EXIT THEN BEGIN ( eat the disabled declaration ) ' ( get the address of the next word ) ['] ; ( get the address of semicolon ) = ( loop until they are equal ) UNTIL ; IMMEDIATE :: FIVE 5 ; ( declares as expected ) FIVE . ( prints 5 ) 1 STAGE ! ( up to here everything's fine ) :: FIVE 6 ; ( is supposed to do nothing, but errors out ) FIVE . ( is supposed to print 5 again )
The traced error message (starting from
1 STAGE !):
Trace: ! Trace: :: Trace: STAGE Trace: @ Trace: (LIT) 0 Trace: = Trace: ?BRANCH Trace: ' Trace: (LIT) 94721509587192 Trace: = Trace: ?BRANCH Trace: ' Word not specified when expected. Trace: ; Compiler word outside definition. Walkback: ;
KEY ( -- ch ) as common in some other Forths for reading a single character from the input stream ( outside the
:: declaration, since it's
IMMEDIATE ) doesn't exist in ATLAST, the only related words I could find are:
': is supposed to read a word from the input stream, then pushes its compile address
'but reads a word from the current line (the inside of the
(STRLIT): are supposed to read literals from the input stream according to the documentation, I could only ever make them segmentation fault, I think they're for compiler-internal use only (e.g., if the compiler encounters a number literal it will compile the
(LIT)word to make it push that number onto the stack)
There aren't any
PARSE either, as in some other Forths.
As you can see,
' is struggling actually getting something from the input stream for some weird reason, and it looks like
['] is failing to capture the
; which then errors out because it's suddenly encountering a
; where it doesn't belong.
I suspect it actually ran
' ['], even though it's supposed to work on the input stream, not the immediate line, and I'm clearly in compile mode there.
I did a similar thing with conditionally declaring variables, there it was rather easy to just
[COMPILE] ' DROP to skip a single word (turning
RES x into
' x DROP), but here I'm pretty sure I can't actually compile those instructions, because I can't emit a loop outside of a declaration. Unless there is a way to somehow compile similar code that recursively gets rid of everything until the
A problem is that
' cannot find a number. A possible solution is to use a special dummy name for the definition, instead of skip it over:
: :: STAGE @ 0 = IF : EXIT THEN ' DROP \ this xt isn't needed " : _dummy" EVALUATE ( -- n ) DROP ;
Or maybe use a new name every time:
: :: STAGE @ 0 = IF : EXIT THEN ' >NAME @ \ ( s1 ) \ should be checked ": _dummy_" DUP >R S+ R> EVALUATE ( -- n ) DROP ;
But due to non standard words it might not work. Another problem is that non colon-definitions are out of the scope.
Perhaps, a better solution is a preprocessing by external means.