'Skip over input stream in ATLAST forth
I'm trying to implement a kind of "conditional :
" in ATLAST, the reasoning being I have a file that gets FLOAD
ed multiple times to handle multiple steps of my program flow (I'm essentially abusing the 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[']
: like'
but reads a word from the current line (the inside of the::
declaration)(LIT)
/(STRLIT)
: are supposed to read literals from the input stream according to the documentation, I could only ever make them segfault, 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's also no WORD
or PARSE
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 someone has an idea how to somehow compile similar code that recursively gets rid of everything until the ;
?
Solution 1:[1]
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.
Solution 2:[2]
It appears that ATLAST is a primitive Forth, that doesn't allow you to go to a more sophisticated handling of sources. But all is not lost! For example a Forth implementation according to ISO standard will handle the matter at ease with one or more of: REQUIRE [IF] [THEN] [DEFINED] SRC >IN NAME WORD FIND As you have a Forth you can steal these words from another Forth and compile the code.
An other solution that may help directly is executing EXIT in interpret mode while loading a file. You have to find out whether you can create a flag whether to abondan the input source. Then the definition might help
: ?abandon IF S" EXIT" EVALUATE THEN ;
S" FIVE" FOUND ?abandon
Note that ?abandon must be executed in interpret mode.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Albert van der Horst |