They can really be nested, right? So there's a REPL that can load files
that can load other files, there is EVALUATE, there are parsing words
that intercept the input stream from when they are invoked, etc. So the current input source has to at least conceptually be maintained on a
stack.
Is there typically an explicit stack for this inside a text interpreter?
Is it normally just done with recursion and the usual D and R stacks?
Using stack juggling in the implementations where the person doesn't
want to use local variables?
Wondering what is usual in this.
restore-input dropthrow ;
They can really be nested, right?
Is there typically an explicit stack for this inside a text interpreter?
Is it normally just done with recursion and the usual D and R stacks?
Using stack juggling in the implementations where the person doesn't
want to use local variables?
They can really be nested, right? So there's a REPL that can load files
that can load other files, there is EVALUATE, there are parsing words
that intercept the input stream from when they are invoked, etc. So the >current input source has to at least conceptually be maintained on a
stack.
Is there typically an explicit stack for this inside a text interpreter?
Is it normally just done with recursion and the usual D and R stacks?
Using stack juggling in the implementations where the person doesn't
want to use local variables?
Wondering what is usual in this.
On Fri, 13 Mar 2026 15:10:13 -0700[...]
Paul Rubin <no.email@nospam.invalid> wrote:
They can really be nested, right?
Check out the standard words SAVE-INPUT and RESTORE-INPUT!
Here is Evaluate from ntf64 as an example
: EVALUATE ( addr u -- )
save-input 2>r
(#src) ! (src) ! 0 >in ! -1 sid ! 0 blk ! ['] refill-evaluate [refill] !
s" Evaluate:" sourcename place
['] interpret catch
dup -1 < if .source then
restore-input dropthrow ;
peter <peter.noreply@tin.it> writes:on LXF64 it outputs adeb and then crashes!
On Fri, 13 Mar 2026 15:10:13 -0700
Paul Rubin <no.email@nospam.invalid> wrote:
[...]They can really be nested, right?
Check out the standard words SAVE-INPUT and RESTORE-INPUT!
I don't think there is anything to check out:
1) If you want to treat RESTORE-INPUT a reliable component (i.e.,
whenever you give it an input produced by SAVE-INPUT, it restores
the input source specification and returns false), I don't see how
to reconcile this with the nesting of INCLUDED, EVALUATE and LOAD.
E.g., consider:
File a.4th:
--------------
.( a)
include b.4th
.( b)
restore-input abort" RESTORE-INPUT cannot restore input source specification"
.( c)
--------------
File b.4th:
-------------
.( d)
save-input
.( e)
what should this code output?
2) OTOH, if you consider the allowance for systems to let
RESTORE-INPUT return true, it is certainly not useful for
implementing INCLUDED and friends, unless you have extra knowledge
about the concrete implementation of SAVE-INPUT and RESTORE-INPUT,
in which case Paul Rubin would have to check out that particular
implementation, not the standard words.
E.g., in Gforth RESTORE-INPUT returns false only if the source-id
is the same as on SAVE-INPUT, so in Gforth SAVE-INPUT and
RESTORE-INPUT are completely useless for implementing INCLUDED and
friends.
In the extreme, the following implementation of these words
satisfies the requirements of the standard, but is absolutely
useless:
: SAVE-INPUT ( -- ) ;
: RESTORE-INPUT ( -- f ) true ;
Actually, looking at <https://forth-standard.org/standard/rationale#rat:core:SAVE-INPUT>, I
find that the committee intended the usage that Gforth supports, and
nothing more. This rationale even claims that a usage that tries to
unnest the input stream using RESTORE-INPUT is non-standard (but I
don't read that out of the normative text).
Here is Evaluate from ntf64 as an example
: EVALUATE ( addr u -- )
save-input 2>r
(#src) ! (src) ! 0 >in ! -1 sid ! 0 blk ! ['] refill-evaluate [refill] !
s" Evaluate:" sourcename place
['] interpret catch
dup -1 < if .source then
restore-input dropthrow ;
It looks like you make use of carnal knowledge about how your
SAVE-INPUT and RESTORE-INPUT is implemented, including knowledge of
the number of stack items pushed by SAVE-INPUT, and DROPping the flag
that indicates the success or failure of RESTORE-INPUT.
- anton
I don't think there is anything typical here, because INCLUDED and
EVALUATE were introduced after the great increase in the number of
Forth systems in the 1980s; so everybody came up with their own implementation.
Gforth currently... forming a stack implemented as a linked list.
while INCLUDED is already running. If you look at the stack effect of INCLUDED, LOAD, and EVALUATE, you will find that they are not allowed
to use the data stack for their storage needs, The return stack is
available for such purposes, however.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
...
while INCLUDED is already running. If you look at the stack effect of
INCLUDED, LOAD, and EVALUATE, you will find that they are not allowed
to use the data stack for their storage needs, The return stack is
available for such purposes, however.
I didn't know about this restriction. It's not mentioned in Docs-html/Forth-source-files.html for gforth 0.7.0 or 0.7.9 at the
moment fwiw. It sounds inconvenient.
On Sat, 14 Mar 2026 15:09:24 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
E.g., consider:on LXF64 it outputs adeb and then crashes!
File a.4th:
--------------
.( a)
include b.4th
.( b)
restore-input abort" RESTORE-INPUT cannot restore input source specification"
.( c)
--------------
File b.4th:
-------------
.( d)
save-input
.( e)
what should this code output?
I think that is expected. It crashes as save-input save the input for b.4th >but include b.4th does a restore input and also closes the b.4th file-mapping >as it is ready using it. when the next restore-input comes it restores again >the input but now the file-mapping is gone and it crashes when reading from >non existing memory.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
I don't think there is anything typical here, because INCLUDED and
EVALUATE were introduced after the great increase in the number of
Forth systems in the 1980s; so everybody came up with their own
implementation.
Ah thanks, I had wondered if there was a traditional approach. But was
there a similar situation with blocks from the very beginning?
If you look at the stack effect of
INCLUDED, LOAD, and EVALUATE, you will find that they are not allowed
to use the data stack for their storage needs, The return stack is
available for such purposes, however.
I didn't know about this restriction. It's not mentioned in >Docs-html/Forth-source-files.html for gforth 0.7.0 or 0.7.9 at the
moment fwiw. It sounds inconvenient.
Given that the intention of SAVE-INPUT and RESTORE-INPUT was to work
within a single input source, I think the better approach would have
been that RESTORE-INPUT produces no flag, but guarantees restoration
as long as you are in the same file, EVALUATE, or LOAD as the
SAVE-INPUT, and throws otherwise (admittedly, exceptions were not
guaranteed in Forth-94).
- anton
Paul Rubin <no.email@nospam.invalid> writes: >>anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
I don't think there is anything typical here, because INCLUDED and
EVALUATE were introduced after the great increase in the number of
Forth systems in the 1980s; so everybody came up with their own
implementation.
Ah thanks, I had wondered if there was a traditional approach. But was >>there a similar situation with blocks from the very beginning?
Forth had blocks already while it was Chuck Moore's language. The
current LOADed block is stored in BLK, and LOAD of course to save BLK
before changing it and restore BLK after the block has been
text-interpreted. And BLK @ BLOCK has to be performed at appropriate
places.
- antonGroetjes Albert
DX-Forth uses a 256 byte return stack. The consequence of that is only
about 6 files can be included before it runs out.
dxf <dxforth@gmail.com> writes:
DX-Forth uses a 256 byte return stack. The consequence of that is only
about 6 files can be included before it runs out.
If you mean 6 levels of nesting, that seems sufficient for a small
system. It's around 20 return stack cells for each level. Is that for
a blocks system, or do you have files?
I guess it's reasonable to set
aside a chunk of dictionary or block space to use as an explicit stack,
if you want to remember filenames.
Do you use RPICK or anything like that, to get at the data for the
current level?
I still don't understand the issue with using the data stack. Maybe I haven't thought about it enough.
It would prevent nested files from passing data on the stack.
Loading works on the principle of a 'current file' whose pointer is saved/restored during nesting.
dxf <dxforth@gmail.com> writes:
...
Loading works on the principle of a 'current file' whose pointer is
saved/restored during nesting.
Ok but in this case why is the return stack depth a limiting factor?
The FDB pointer is just one cell, maybe even a static cell. Then you
have an array of FDB's that is used as a stack with the FDB pointer as a stack pointer, if I understand what you mean.
in blk etc). Then there's RS usage incurred during load/compile ofthe current file. It all adds up. My ?STACK does a RS check which is
For each nest there's state stuff that needs saving (loadline# source
in blk etc).
Then there's RS usage incurred during load/compile of the current
file. It all adds up.
dxf <dxforth@gmail.com> writes:
For each nest there's state stuff that needs saving (loadline# source
in blk etc).
Oh I had figured that would be in the FDB. Does it have to be on the
stack for some reason?
Then there's RS usage incurred during load/compile of the current
file. It all adds up.
I wonder if moving the state to the FDB can get rid of the need for
stack nesting. Then it's just a matter of how many FDB's you want to
set aside space for. You could even put them in the ALLOCATE heap if
you have that.
I'd have to think how that could be made to work. OTOH RS exists and
as its entire purpose is nesting, why wouldn't I use it?
I don't have ALLOCATE for various reasons. It's always struck me as
black magic.
dxf <dxforth@gmail.com> writes:
I'd have to think how that could be made to work. OTOH RS exists and
as its entire purpose is nesting, why wouldn't I use it?
Do you have to do a bunch of painful juggling to get at the several
relevant RS items? And as you say, it limits you to 6 levels.
I don't have ALLOCATE for various reasons. It's always struck me as
black magic.
It gets worse. Don't ever let anyone tell you about garbage collection ;).
dxf <dxforth@gmail.com> writes:
For each nest there's state stuff that needs saving (loadline# source
in blk etc).
Oh I had figured that would be in the FDB. Does it have to be on the
stack for some reason?
Then there's RS usage incurred during load/compile of the current
file. It all adds up.
I wonder if moving the state to the FDB can get rid of the need for
stack nesting. Then it's just a matter of how many FDB's you want to
set aside space for. You could even put them in the ALLOCATE heap if
you have that.
In article <87jyvbcth2.fsf@nightsong.com>,
Paul Rubin <no.email@nospam.invalid> wrote:
dxf <dxforth@gmail.com> writes:
For each nest there's state stuff that needs saving (loadline# source
in blk etc).
Oh I had figured that would be in the FDB. Does it have to be on the
stack for some reason?
Then there's RS usage incurred during load/compile of the current
file. It all adds up.
I wonder if moving the state to the FDB can get rid of the need for
stack nesting. Then it's just a matter of how many FDB's you want to
set aside space for. You could even put them in the ALLOCATE heap if
you have that.
Somehow in addition to buffer information you must remember the
file identification. For unix and linux that is a handle that you
get back from OPEN-FILE. That is readily stored on the return stack,
if you are not in a pinch (on a 64 bit system). If you store this in
FDB still you have stack a reference to the FDB. I don't think you
can use the data stack for that.
Groetjes Albert
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,102 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 492328:10:49 |
| Calls: | 14,132 |
| Calls today: | 2 |
| Files: | 186,278 |
| D/L today: |
3,501 files (1,225M bytes) |
| Messages: | 2,501,393 |