wmb@MITCH.ENG.SUN.COM (07/06/90)
> You can push the jmp_buf on the return stack.
You can do so if you happen to know how many return stack cells are
necessary to hold the information in jmp_buf. Since the size of
jmp_buf is not necessarily the same for all systems, the portable code
for doing so looks like:
#JMP_BUF BEGIN JMP_BUF OVER CELLS+ @ >R 1- DUP 0< UNTIL
and the popping code which is required at the end is of similar ilk.
And you can't build this code inside a colon definition because a
standard program cannot make detailed assumptions about exactly
what happens to the return stack when a colon definition is called.
In particular, : FOO R> {push stuff on the return stack} >R ;
isn't guaranteed to be portable.
Note that you can't use a DO .. LOOP for the above code because you can't
shove stuff on the return stack inside a DO .. LOOP . Which brings up the
other obvious problem with using the return stack in this fashion; it
"partitions" the return stack in the middle of a definition, so that
anything that is placed on the return stack before the jmp_buf stuff
is put there becomes inaccessible while the jmp_buf stuff is there.
CATCH/THROW avoids this partitioning effect by making the return stack
effects occur at a procedure boundary, where the return stack details
are already hidden from a standard program.
Specifying that the JMP_BUF information "must be" e.g. 2 cells worth of
data would work in some systems, and would simplify the jmp_buf save
code to
JMP_BUF 2@ 2>R
but the restriction to 2 cells is impractical, because many systems will
need to save additional information, such as a floating point stack pointer
or a local variable frame pointer.
Mitch
peter@ficc.ferranti.com (Peter da Silva) (07/07/90)
In article <9007062100.AA05671@ucbvax.Berkeley.EDU> wmb%MITCH.ENG.SUN.COM@SCFVM.GSFC.NASA.GOV writes: > > You can push the jmp_buf on the return stack. > You can do so if you happen to know how many return stack cells are > necessary to hold the information in jmp_buf. True. You also need to know this to allocate a jmp_buf, so it's reasonable to assume you know it or can find out: HERE allocate jmp_buf HERE SWAP - CONSTANT JMP_BUF_SIZE > Which brings up the > other obvious problem with using the return stack in this fashion; it > "partitions" the return stack in the middle of a definition, Since you're doing it to implement catch/throw you can assume that this is a reasonable assumption. > CATCH/THROW avoids this partitioning effect by making the return stack > effects occur at a procedure boundary, where the return stack details > are already hidden from a standard program. But you can't use CATCH and THROW to (for example) implement coroutines. This does require knowing what's inside a JMP_BUF, I admit, but that's probably manageable: addr JMP_BUF !STACK_BASE addr JMP_BUF !RSTACK_BASE int JMP_BUF !STACK_SIZE int JMP_BUF !RSTACK_SIZE addr JMP_BUF !IP JMP_BUF longjmp This is forth. If you want a language like lisp with no interesting bits, I'd say go with lisp. For forth you should choose the mechanism with the greatest amount of flexibility. Ten years ago I did this both ways, and jmp_buf was the clear winner. -- Peter da Silva. `-_-' +1 713 274 5180. <peter@ficc.ferranti.com>