Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Implementation of LEAVE?

300 views
Skip to first unread message

alexin...@gmail.com

unread,
Jun 23, 2016, 5:01:36 AM6/23/16
to
Dear comp.lang.forth,

Greetings! I'm hoping one of you Forth wizards can enlighten me on the most practical way to implement (ANS Forth) LEAVE. (I'm implementing Forth as a way of learning about it.)

IF..ELSE..THEN, BEGIN..AGAIN, BEGIN..WHILE..REPEAT, etc. all use the data stack to store unresolved jump origins and destinations. But because LEAVE follows a different nesting discipline from all of these other control flow structures, it can't use the data stack to store its jump origin, or things get messed up when (for example) you put a LEAVE inside an IF..THEN block.

I have read that some Forths use the retstack for storing LEAVE jump origins, then resolve all of them when the corresponding LOOP or +LOOP is reached. This seems to make sense.

But then I have also read things like this:

(http://www.figuk.plus.com/build/heart.htm)
The behaviour of ?DO and LEAVE has led to some strange
implementations. For example, F83 DO pushes the exit
address of the loop on the return stack so that it can
be picked up and used by LEAVE, and it does so whether
that particular loop has a LEAVE or not. This version
is more rational. LEAVE compiles its own exit address
and doesn't mess with the return stack.

And:

("The Forth Course" by Richard Haskell, Lesson 9)
Having the value of xhere2 as the third item on the return
stack is used by LEAVE to find the address to leave to.

Neither of these make the slightest bit of sense to me. How can LEAVE compile its own exit address, when the corresponding LOOP or +LOOP hasn't been seen yet?

And how can the address which Mr. Haskell calls "xhere2" (the address of the code immediately following DO) be of any use to LEAVE, when LEAVE should transfer control *past* the end of DO..LOOP, not to the beginning of the loop body?

Any other notes on how to best implement LEAVE would be appreciated. Thanks, Alex Dowad

Andrew Haley

unread,
Jun 23, 2016, 6:46:06 AM6/23/16
to
alexin...@gmail.com wrote:
> Dear comp.lang.forth,
>
> Greetings! I'm hoping one of you Forth wizards can enlighten me on the most practical way to implement (ANS Forth) LEAVE. (I'm implementing Forth as a way of learning about it.)
>
> IF..ELSE..THEN, BEGIN..AGAIN, BEGIN..WHILE..REPEAT, etc. all use the
> data stack to store unresolved jump origins and destinations. But
> because LEAVE follows a different nesting discipline from all of
> these other control flow structures, it can't use the data stack to
> store its jump origin, or things get messed up when (for example)
> you put a LEAVE inside an IF..THEN block.

The simplest thing to do at compile time is to give every kind of
control structure a unique tag which is on top of the address.

So:

: if ( - a n) here 1 ;
: do ( - a n) postpone (do) here 2 ;

... etc.

Then, when compiling LEAVE, search down the stack for the tag left by
DO. Insert an address and a leave tag, and restore all the stack
items on top. Then the compile-time action of LOOP pops as many LEAVE
addresses as it finds on the stack and resolves them.

Andrew.

Anton Ertl

unread,
Jun 23, 2016, 7:53:33 AM6/23/16
to
alexin...@gmail.com writes:
>But then I have also read things like this:
>
> (http://www.figuk.plus.com/build/heart.htm)
> The behaviour of ?DO and LEAVE has led to some strange
> implementations. For example, F83 DO pushes the exit
> address of the loop on the return stack so that it can
> be picked up and used by LEAVE, and it does so whether
> that particular loop has a LEAVE or not. This version
> is more rational. LEAVE compiles its own exit address
> and doesn't mess with the return stack.
>
>And:
>
> ("The Forth Course" by Richard Haskell, Lesson 9)
> Having the value of xhere2 as the third item on the return
> stack is used by LEAVE to find the address to leave to.
>
>Neither of these make the slightest bit of sense to me. How can LEAVE compi=
>le its own exit address, when the corresponding LOOP or +LOOP hasn't been s=
>een yet?

Somehow I miss the code that this comment is referring to, but anyway,
my guess is that he means that LEAVE compiles a BRANCH to behind the
LOOP, rather than taking the exit address from the return stack.
Doing that has its own interesting issues. A popular approach is to
chain all the LEAVEs together using the target address fields of the
BRANCHes), and, when encountering the LOOP, walk the chain and fill
the target address fields with the correct target.

>And how can the address which Mr. Haskell calls "xhere2" (the address of th=
>e code immediately following DO) be of any use to LEAVE, when LEAVE should =
>transfer control *past* the end of DO..LOOP, not to the beginning of the lo=
>op body?

One possibility is that the DO run-time code contains the address
behind the LOOP in some way (the ?DO run-time code certainly does),
and LEAVE can use the DO address to find that.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2016: http://www.euroforth.org/ef16/

Anton Ertl

unread,
Jun 23, 2016, 7:57:18 AM6/23/16
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>Then, when compiling LEAVE, search down the stack for the tag left by
>DO. Insert an address and a leave tag, and restore all the stack
>items on top. Then the compile-time action of LOOP pops as many LEAVE
>addresses as it finds on the stack and resolves them.

Not really in line with the standard compilation stack effect of
LEAVE, which is ( -- ), but it would probably work. I don't find it
particularly simple, however, rather to the contrary.

Andrew Haley

unread,
Jun 23, 2016, 1:06:12 PM6/23/16
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>Then, when compiling LEAVE, search down the stack for the tag left by
>>DO. Insert an address and a leave tag, and restore all the stack
>>items on top. Then the compile-time action of LOOP pops as many LEAVE
>>addresses as it finds on the stack and resolves them.
>
> Not really in line with the standard compilation stack effect of
> LEAVE, which is ( -- ),

Bah. Broken standard. :-)

> but it would probably work. I don't find it particularly simple,
> however, rather to the contrary.

Assuming that you already have the tags in order to do some checking,
it doesn't strike me as being very hard. I can't think of anything
significantly simpler. I guess there's chaining the LEAVEs through
memory if there's room, but that's not all that simple either.

Andrew.

Paul Rubin

unread,
Jun 23, 2016, 3:19:56 PM6/23/16
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> Assuming that you already have the tags in order to do some checking,
> it doesn't strike me as being very hard.

How do you scan the stack to look for the tags? With PICK? By copying
to memory? Copying to the return stack sounds tricky, depending on how
loops are implemented.

Andrew Haley

unread,
Jun 24, 2016, 4:05:40 AM6/24/16
to
Remember that we're talking about *compile time*. All we have to
manipulate is a bunch of addresses to be resolved. Scanning down in
order to stash a LEAVE tag can be done recursively.

Andrew.

Anton Ertl

unread,
Jun 24, 2016, 12:30:30 PM6/24/16
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>>Then, when compiling LEAVE, search down the stack for the tag left by
>>>DO. Insert an address and a leave tag, and restore all the stack
>>>items on top. Then the compile-time action of LOOP pops as many LEAVE
>>>addresses as it finds on the stack and resolves them.
[...]
>> I don't find it particularly simple,
>> however, rather to the contrary.
>
>Assuming that you already have the tags in order to do some checking,
>it doesn't strike me as being very hard. I can't think of anything
>significantly simpler. I guess there's chaining the LEAVEs through
>memory if there's room, but that's not all that simple either.

With your solution LEAVE needs to search the data stack, and save and
restore the data that is there, much more complex than inserting an
entry into a linked list.

Apart from that, no, you cannot use the tags for finding the do-sys,
because the user can push things on the data stack that look like the
tag. You can have a variable that contains the depth of the innermost
do-sys, though.

Anyway, not simple.

alexin...@gmail.com

unread,
Jun 24, 2016, 7:30:06 PM6/24/16
to
Andrew, Anton, and others, thanks very much for your enlightening comments!

Anton, the idea of using the destination fields of the BRANCHes as a linked list is very clever! My question, though, is: where do you store the head of the list? It has to be somewhere where:

1. LEAVE can easily find it
2. LOOP/+LOOP can easily find it

If you put it on the data stack, we are just back to the same old problem that we were trying to get away from. If you put it on the retstack, that would work, but it has its own problems. Stashing stuff on the retstack makes it more difficult to compose words (unless you get rid of the stashed data within the same word which put it there).

If you put it in a VARIABLE, you now have problems when nesting DO..LOOP blocks. Because using a single, static location in memory as the list head doesn't allow you to have more than one such list at the same time. And you need to have one linked list for *each* DO..LOOP block which is still incomplete.

Unless you build *another* linked list of incomplete DO structures, that is. Then you have a linked list of linked lists, and things are starting to get complicated. OR, you could have special 'delimiter' nodes in the linked list that demarcate which nodes belong to the innermost incomplete DO..LOOP block. That sounds complicated too.

OR, you use an ARRAY or some such to hold the heads of the linked lists. Now nesting is no problem. But if you use an ARRAY, you might as well just create a special software stack exclusively used for compiling (possibly nested) DO..LOOP structures.

Anton, can you please share with us: how does GForth do it?

I am thinking that the solution which allows for the cleanest and simplest compiler code is: add a special "control-flow stack", possibly with specialized primitives for accessing it. This stack is exclusively used for compiling control-flow structures like IF..THEN, BEGIN..UNTIL, DO..LOOP, and so on.

Then "tag" all the data which goes on this stack, as Andrew suggested. Perhaps the primitives which are used to access this stack can *enforce* the proper use of tags. Then there is no problem of "the user pushing things on the stack which look like the tag".

Thanks again, all!
AD

Brad Eckert

unread,
Jun 24, 2016, 7:30:45 PM6/24/16
to
On Thursday, June 23, 2016 at 2:01:36 AM UTC-7, Alex Dowad wrote:
> Dear comp.lang.forth,
>
> Greetings! I'm hoping one of you Forth wizards can enlighten me on the most practical way to implement (ANS Forth) LEAVE. (I'm implementing Forth as a way of learning about it.)
>

Hmm, I had to look at my Forth. It uses a separate stack for LEAVEs.

create xpad 260 allot \ scratchpad...
variable xsp
: xsp0 ( -- ) xpad 256 + xsp ! ; \ clear the LEAVE list
: xsp! ( n -- ) [ -1 cells ] literal xsp +! xsp @ ! ; \ to LEAVE stack
: xsp@ ( -- n ) xsp @ @ [ 1 cells ] literal xsp +! ; \ from LEAVE stack

: _resloop ( bj -- ) \ resolve loop/+loop
8 ?pairs s" ~0BRAN" cop <resolve
begin xpad 256 + xsp @ - while xsp@ >resolve repeat
s" UNLOOP" cop ;

: DO ( -- bj ) xsp0 S" _DO" cop <mark 8 ; immediate
: LEAVE ( -- ) S" ~BRAN" cop >mark xsp! ; immediate
: LOOP ( bj -- ) S" _LOOP" cop _resloop ; immediate

JennyB

unread,
Jun 24, 2016, 7:53:11 PM6/24/16
to
How does the following THEN resolve if LEAVE adds to the control stack? LEAVE would have tuck it under the forward branch reference, much like WHILE does.

I've never seen this construction used:

IF ... IF ... LEAVE THEN ... THEN

but it does work with the standard spec of LEAVE and it won't with this.

If that does not matter then it suggests an ELSE for WHILE

: DONE 1 CS-ROLL POSTPONE ELSE ; IMMEDIATE

That would make the baroque:

BEGIN not-a WHILE
... b UNTIL ." exit on b"
ELSE ." exit on a" THEN

a more readable
BEGIN a IF ." exit on a" DONE
.. b UNTIL ." exit on b" THEN

Then if your do-sys was the same size as your begin-sys you could use DONE and UNLOOP instead of LEAVE

DO ... a IF ." exit on a" UNLOOP DONE
LOOP
." a not found" THEN

which is quite hard to code otherwise.





JennyB

unread,
Jun 24, 2016, 7:58:01 PM6/24/16
to
On Friday, 24 June 2016 09:05:40 UTC+1, Andrew Haley wrote:
You only need to scan down the stack if you are allowing constructions like

IF ... IF LEAVE THEN THEN

I don't think I've ever seen that used, but I may be wrong.

minf...@arcor.de

unread,
Jun 24, 2016, 7:59:56 PM6/24/16
to
My Forth is a simple implementation and LEAVE has no special compile-time beahvioir like raking addresses from the return stack:

: LEAVE \ ( -- ) leave the do-loop immediately (jump back to (DO))
2r> 2drop 0 >r 2 rpick >r -1 ;

in combination with

: DO \ ( limit start -- ) set up a do-loop which will terminate if
\ the index crosses between limit and limit-1
postpone (do) >mark postpone (jmpv) ; IMMEDIATE

: (DO) \ ( lim st -- 0 | i lim here ) set up loop parameters on ret.stack
swap dup >r - >r 2 rpick >r 0 ;

: >MARK \ ( -- adr ) mark a forward jump
here ;

(jmpv) is a primitive that checks and jumps when the loop index crosses borders

Not pretty but simple and it just works ;-)

JennyB

unread,
Jun 24, 2016, 8:07:15 PM6/24/16
to
On Friday, 24 June 2016 09:05:40 UTC+1, Andrew Haley wrote:
Simpler yet, as with WHILE, have LEAVE tuck its orig under the do-sys. That would work in most cases, except for something like

IF ... IF ... LEAVE THEN THEN

but have you ever seen that actually used?


Anton Ertl

unread,
Jun 25, 2016, 1:37:42 AM6/25/16
to
alexin...@gmail.com writes:
>Andrew, Anton, and others, thanks very much for your enlightening comments!
>
>Anton, the idea of using the destination fields of the BRANCHes as a linked=
> list is very clever! My question, though, is: where do you store the head =
>of the list? It has to be somewhere where:
>
>1. LEAVE can easily find it
>2. LOOP/+LOOP can easily find it
...
>If you put it in a VARIABLE, you now have problems when nesting DO..LOOP bl=
>ocks.

Yes, but that is solvable in two ways (in addition to the ones you
outlined):

1) Save the old contents of the variable in the do-sys (in DO), and
restore it in LOOP.

2) Just link all the unresolved LEAVEs together (from the latest one
to the earlierst one). Upon LOOP, follow the chain, but stop when you
reach a LEAVE that has a lower address than the DO.

>Anton, can you please share with us: how does GForth do it?

Because we have automatic scoping of locals, we have more information
to manage than can easily fit in a cell, so we use a separate leave
stack. To determine which leave stack item belongs to which DO, we
check whether the address of the LEAVE is between the DO and the LOOP
we currently want to resolve (i.e., similar to option 2 above).

>Then "tag" all the data which goes on this stack, as Andrew suggested. Perh=
>aps the primitives which are used to access this stack can *enforce* the pr=
>oper use of tags. Then there is no problem of "the user pushing things on t=
>he stack which look like the tag".

Yes, that would work. As mentioned, we have a separate stack, but we
only have the LEAVEs there. This is simpler by not having to shuffle
unrelated control-flow stack items around for dealing with LEAVE.

Andrew Haley

unread,
Jun 25, 2016, 5:19:36 AM6/25/16
to
JennyB <jenny...@googlemail.com> wrote:
> On Friday, 24 June 2016 09:05:40 UTC+1, Andrew Haley wrote:
>> Paul Rubin <no.e...@nospam.invalid> wrote:
>> > Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>> >> Assuming that you already have the tags in order to do some checking,
>> >> it doesn't strike me as being very hard.
>> >
>> > How do you scan the stack to look for the tags? With PICK? By
>> > copying to memory? Copying to the return stack sounds tricky,
>> > depending on how loops are implemented.
>>
>> Remember that we're talking about *compile time*. All we have to
>> manipulate is a bunch of addresses to be resolved. Scanning down in
>> order to stash a LEAVE tag can be done recursively.
>
> How does the following THEN resolve if LEAVE adds to the control stack?

The idea is that LEAVE puts its data on top of the first DO it finds
on the stack. LOOP resolves all of the LEAVEs it finds.

Andrew.

JennyB

unread,
Jun 25, 2016, 6:38:39 AM6/25/16
to
I see. Yes, that is Standard, if you define do-sys as including the LEAVE data. That's OK because you can't portably access anything below a do-sys until it is consumed. I still think the chaining method that Anton describes is simpler, though.

JennyB

unread,
Jun 25, 2016, 6:49:46 AM6/25/16
to
On Saturday, 25 June 2016 00:53:11 UTC+1, JennyB wrote:

> Then if your do-sys was the same size as your begin-sys you could use DONE and UNLOOP instead of LEAVE
>
> DO ... a IF ." exit on a" UNLOOP DONE
> LOOP
> ." a not found" THEN
>
> which is quite hard to code otherwise.

My brain wasn't working yesterday, partly because Google Groups keep delaying my posts. The above can of course be coded using UNLOOP EXIT. I still like DONE with BEGIN, but the only reason you might need it in a counted loop would be because you had common code that was shared by multiple early exits and not by the normal exit. That would be too much to try to write in one word anyway.

Mark Wills

unread,
Jun 25, 2016, 10:51:07 AM6/25/16
to
My system is dead simple. On my system, (DO) pushes three cells onto the return address:

cell 0 : index (used by I, LOOP, +LOOP)
cell 1 : loop back address (used by LOOP and +LOOP to execute the loop again)
cell 2 : exit address - the address just after LOOP or +LOOP

Mark Wills

unread,
Jun 25, 2016, 11:29:31 AM6/25/16
to
On Thursday, 23 June 2016 10:01:36 UTC+1, Alex Dowad wrote:
See here: http://turboforth.net/source/Bank0/0-05-FlowControl.html

Andrew Haley

unread,
Jun 25, 2016, 12:00:28 PM6/25/16
to
JennyB <jenny...@googlemail.com> wrote:
>
> I see. Yes, that is Standard, if you define do-sys as including the
> LEAVE data. That's OK because you can't portably access anything
> below a do-sys until it is consumed. I still think the chaining
> method that Anton describes is simpler, though.

Quite possibly so, although I'd imagine it's not a huge deal
different.

As an aside, I can't immediately think of any use for LEAVE, given
that since ANS we've had UNLOOP EXIT, and the need to factor out the
loop into its own definition doesn't strike me as particlarly onerous.
I suppose some people might not like to exit a word in the middle.

These days, given quotations, it's easy to write the sort of thing for
which LEAVE might be useful as

[:
do
i find-thing if
found-actions
unloop exit then
loop
fail-actions
;] execute

(Here, EXIT is no more than a way to get out of a deeply nested
control structure, and is like polyFORTH's DO ... WHILE ... LOOP --
which I didn't very often use but really liked.)

Quotations for the win! :-)

... as opposed to using LEAVE:

true
do
i find-thing if
found-actions
drop false leave then
loop
if fail-actions then

Andrew.

Anton Ertl

unread,
Jun 25, 2016, 1:41:00 PM6/25/16
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>These days, given quotations, it's easy to write the sort of thing for
>which LEAVE might be useful as
>
> [:
> do
> i find-thing if
> found-actions
> unloop exit then
> loop
> fail-actions
> ;] execute

The usual misgiving I have about using EXIT is that it means that I
have a chance to not see some exit in debugging because I forget to
put a tracer before every EXIT, but in this case I can just put the
tracer after the EXECUTE, and everything will be fine.

Efficiency on simple implementations may be an issue, though.

>Quotations for the win! :-)

If we can manage to convince you, there is still hope for humanity:-)

Anyway, maybe time for Alex McDonald (is he still active?) to update
the RfD (if necessary) and submit a CfV in time for the upcoming
meeting.

Coos Haak

unread,
Jun 25, 2016, 6:37:58 PM6/25/16
to
Op Sat, 25 Jun 2016 07:51:05 -0700 (PDT) schreef Mark Wills:
Don't you need a fourth cell containing the limit of the loop (of some
form, some Forth's manipulate the highest bit for example) to be checked
by LOOP and +LOOP ?
Your cell 1 can be combined when compliling LOOP or +LOOP so it
does not occupy space on the return stack.

groet Coos

HAA

unread,
Jun 26, 2016, 1:29:34 AM6/26/16
to
alexin...@gmail.com wrote:
> Dear comp.lang.forth,
>
> Greetings! I'm hoping one of you Forth wizards can enlighten me on the most practical
> way to implement (ANS Forth) LEAVE. (I'm implementing Forth as a way of learning about
> it.)
>
> IF..ELSE..THEN, BEGIN..AGAIN, BEGIN..WHILE..REPEAT, etc. all use the data stack to
> store unresolved jump origins and destinations. But because LEAVE follows a different
> nesting discipline from all of these other control flow structures, it can't use the
> data stack to store its jump origin, or things get messed up when (for example) you put
> a LEAVE inside an IF..THEN block.
>
> I have read that some Forths use the retstack for storing LEAVE jump origins, then
> resolve all of them when the corresponding LOOP or +LOOP is reached. This seems to make
> sense.
>
> But then I have also read things like this:
>
> (http://www.figuk.plus.com/build/heart.htm)
> The behaviour of ?DO and LEAVE has led to some strange
> implementations. For example, F83 DO pushes the exit
> address of the loop on the return stack so that it can
> be picked up and used by LEAVE, and it does so whether
> that particular loop has a LEAVE or not. This version
> is more rational. LEAVE compiles its own exit address
> and doesn't mess with the return stack.

It doesn't need to be complicated. This one is for ITC/DTC. Compiler security
checking not shown.

0 value leav
: DO postpone (do) leav >mark dup to leav postpone begin ; immediate
: ?DO postpone (?do) leav >mark dup to leav postpone begin ; immediate
: LEAVE postpone (leave) leav , ; immediate
: LOOP postpone (loop) <resolve postpone then to leav ; immediate
: +LOOP postpone (+loop) <resolve postpone then to leav ; immediate



Anton Ertl

unread,
Jun 26, 2016, 6:19:56 AM6/26/16
to
"HAA" <som...@microsoft.com> writes:
>It doesn't need to be complicated. This one is for ITC/DTC. Compiler security
>checking not shown.
>
>0 value leav
>: DO postpone (do) leav >mark dup to leav postpone begin ; immediate
>: ?DO postpone (?do) leav >mark dup to leav postpone begin ; immediate
>: LEAVE postpone (leave) leav , ; immediate
>: LOOP postpone (loop) <resolve postpone then to leav ; immediate
>: +LOOP postpone (+loop) <resolve postpone then to leav ; immediate

It looks to me like your LEAVEs point to the DO, and find the target
address there. This means that (LEAVE) has one indirection more than
BRANCH, which also explains why you have a separate (LEAVE).
Certainly simpler than using BRANCH and filling in the branch target
at compile time, but this simplicity comes at a run-time cost.

Andrew Haley

unread,
Jun 26, 2016, 1:14:49 PM6/26/16
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>
>>Quotations for the win! :-)
>
> If we can manage to convince you, there is still hope for humanity:-)

OK, I guess that was a joke, but if so I don't get it. I
always argued for quatations.

> Anyway, maybe time for Alex McDonald (is he still active?) to update
> the RfD (if necessary) and submit a CfV in time for the upcoming
> meeting.

The RfD looked pretty clean the last time I saw it.

Andrew.

Alex Dowad

unread,
Jun 26, 2016, 4:53:41 PM6/26/16
to
Thanks all for the interesting and informative posts. I ended up using Andrew Haley's suggestion, combined with a special-purpose control-flow stack where all unresolved jump origins/destinations are tagged. It's sweet; the CF-related code reads really well now.

Thanks again! Alex

hughag...@gmail.com

unread,
Jun 26, 2016, 7:36:41 PM6/26/16
to
On Sunday, June 26, 2016 at 10:14:49 AM UTC-7, Andrew Haley wrote:
> Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> > Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> >
> >>Quotations for the win! :-)
> >
> > If we can manage to convince you, there is still hope for humanity:-)
>
> OK, I guess that was a joke, but if so I don't get it. I
> always argued for quatations.

All of the ANS-Forth cult members have argued in favor of the Paysan-faked quotations that lack access to the parent function's local variables.

> > Anyway, maybe time for Alex McDonald (is he still active?) to update
> > the RfD (if necessary) and submit a CfV in time for the upcoming
> > meeting.
>
> The RfD looked pretty clean the last time I saw it.

Bernd Paysan wrote the Paysan-faked quotation code, but he couldn't write the RfD because Forth-200x is astro-turfed (it is a corporate project that is faked up to look like a grass-roots project) and so the RfDs are supposed to be written by common Forth programmers. Because of this, Alex McDonald put his name on the RfD and pretended that it was his.

The RfD was guaranteed to be accepted because the code was written by a committee member to the spec that came from Leon Wagner --- it would have been a slam-dunk from a ladder for Alex McDonald --- but then Alex McDonald disappeared, so now the RfD is left hanging in limbo with nobody to put their name on it.

Alex McDonald listed my name as a contributor on the RfD. I said that I would sue for libel if the Forth-200x committee used my name. Shortly after this, Alex McDonald disappeared. Most likely, the Forth-200x committee told him that he was too dumb even for the super-simple job of pushing through an RfD that has been pre-approved, and that he was exposing Forth-200x to a lawsuit, so he got pulled from the RfD. They may have also been paying him for his work, faking up the grass-roots concept of Forth-200x, and harassing the Forth-200x critics (he told me: "you have a serious misunderstanding of how pointers work"). If they were paying him and they stopped, then this is a big part of why he left.

Alex McDonald is not going to come back and take over the RfD again. He dropped the ball. The Forth-200x committee needs somebody else to put their name on the RfD now. I predict that Andrew Haley will get appointed to this job.

Alex McDonald is still lurking on c.l.f. --- he sent me a death threat recently:
---------------------------------------------------------------------------
Unfortunately, you're still here, and I suspect you won't do me the tremendous favour of fucking off or dieing any time soon. Ah well.

I still occasionally read clf. Personal reasons and your continued existence have stopped me being an active contributor. I'll continue to lurk for the moment.
---------------------------------------------------------------------------

He was mad about this thread:
https://groups.google.com/forum/#!topic/comp.lang.forth/3LSqmBIZuzY%5B76-100%5D
In this thread HumptyDumpty implemented quotations that have access to the parent function's local variables. I upgraded his code slightly to allow the HOF to have local variables of its own. I did this with some VFX-specific assembly-language code --- HumptyDumpty's code was already in violation of ANS-Forth anyway --- if you are going to be non-standard anyway, you might as well just go ahead and use assembly-language.

: rexit ( -- ) rdrop ;
: (r:) ( -- r ) r@ 5 + ; \ 5 is the size of a JMP instruction in 32-bit x86
: r[ ( -- r ) postpone (r:) postpone ahead ; immediate
: ]r ( -- ) postpone rexit postpone then ; immediate

code rex ( r -- ) \ HumptyDumpty called this RCALL --- REX means "R execute"
push edi \ this is the HOF's LF which won't be used by the quotation
mov edi, 0 [edi] \ this is the parent's LF which will be used by the quotation
call ' execute
pop edi \ restore HOF's LF
next, end-code

hughag...@gmail.com

unread,
Jun 26, 2016, 8:57:24 PM6/26/16
to
I forgot when I wrote this that Andrew Haley is a member of the Forth-200x committee, so he can't put his name on the RfD either --- it has to be a non-member who puts his name on the RfD in order to fake up the illusion that these RfDs don't come directly from the Forth-200x committee but come from the Forth community instead.

So, I change my prediction --- it will be Rickman who puts his name on the RfD for the Paysan-faked quotations --- he is not a committee member --- he can pretend to represent the Forth community (claim that the Forth community wants Paysan-faked quotations).

HAA

unread,
Jun 27, 2016, 8:36:45 AM6/27/16
to
Anton Ertl wrote:
> "HAA" <som...@microsoft.com> writes:
> >It doesn't need to be complicated. This one is for ITC/DTC. Compiler security
> >checking not shown.
> >
> >0 value leav
> >: DO postpone (do) leav >mark dup to leav postpone begin ; immediate
> >: ?DO postpone (?do) leav >mark dup to leav postpone begin ; immediate
> >: LEAVE postpone (leave) leav , ; immediate
> >: LOOP postpone (loop) <resolve postpone then to leav ; immediate
> >: +LOOP postpone (+loop) <resolve postpone then to leav ; immediate
>
> It looks to me like your LEAVEs point to the DO, and find the target
> address there.

Yes. Conveniently it also happens be the location (?do) uses to exit
when index and limit are equal.

> This means that (LEAVE) has one indirection more than
> BRANCH, which also explains why you have a separate (LEAVE).
> Certainly simpler than using BRANCH and filling in the branch target
> at compile time, but this simplicity comes at a run-time cost.

All things considered there is no cost. There is one extra jump *if* you
LEAVE the loop. It quickly pales into insignificance when you consider
what's happening inside the loop including the IF LEAVE THEN and LOOP
which represent two tests and jumps *every* time you don't exit.



Alex McDonald

unread,
Jun 27, 2016, 9:16:18 AM6/27/16
to
I'm still here. For many reasons, I'm unable to take it forward right
now, but if anyone else would like to do so, I would welcome it.

Anton Ertl

unread,
Jun 27, 2016, 10:39:52 AM6/27/16
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>
>>>Quotations for the win! :-)
>>
>> If we can manage to convince you, there is still hope for humanity:-)
>
>OK, I guess that was a joke, but if so I don't get it. I
>always argued for quatations.

Maybe I just confused you with someone who had argued against. Too
bad: No convincing, no hope for humanity:-).

>> Anyway, maybe time for Alex McDonald (is he still active?) to update
>> the RfD (if necessary) and submit a CfV in time for the upcoming
>> meeting.
>
>The RfD looked pretty clean the last time I saw it.

Pretty much. The only comment I had was that one also would need to
refine DOES> in order to actually do what he outlines in the
discussion. However, looking at the current practice (divergent, see
below), and the lack of usage of RECURSE after DOES>, I think it's
better not to include such a change in the quotations RfD.

Current practice: For

: foo ( A ) DOES> ( B ) RECURSE ;

Gforth 0.7.0 and SwiftForth compile the RECURSE into a call of FOO.
VFX reports an error. The current development version of Gforth
compiles a call to the definition starting right after DOES>. We made
this change in Gforth, because it fits our new implementation approach
better, and we believe that nobody uses RECURSE after DOES> in
production code.

Andrew Haley

unread,
Jun 27, 2016, 12:05:43 PM6/27/16
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>
>>> Anyway, maybe time for Alex McDonald (is he still active?) to update
>>> the RfD (if necessary) and submit a CfV in time for the upcoming
>>> meeting.
>>
>>The RfD looked pretty clean the last time I saw it.
>
> Pretty much. The only comment I had was that one also would need to
> refine DOES> in order to actually do what he outlines in the
> discussion. However, looking at the current practice (divergent, see
> below), and the lack of usage of RECURSE after DOES>, I think it's
> better not to include such a change in the quotations RfD.

I agree.

> Current practice: For
>
> : foo ( A ) DOES> ( B ) RECURSE ;
>
> Gforth 0.7.0 and SwiftForth compile the RECURSE into a call of FOO.
> VFX reports an error. The current development version of Gforth
> compiles a call to the definition starting right after DOES>. We
> made this change in Gforth, because it fits our new implementation
> approach better, and we believe that nobody uses RECURSE after DOES>
> in production code.

Indeed. When cross-compiling, the first part of FOO executes on the
host and the part after DOES> executes on the target. It makes no
sense at all for RECURSE in the target's runtime action to call a
compiler word. I know that we're not creating a cross-compiler, but
this behaviour should at least make sense, IMO.

An error message is best of all.

Andrew.

Anton Ertl

unread,
Jun 27, 2016, 12:13:39 PM6/27/16
to
Alex McDonald <al...@rivadpm.com> writes:
[Quotations RfD]
>I'm still here. For many reasons, I'm unable to take it forward right
>now, but if anyone else would like to do so, I would welcome it.

I'll jump in, unless someone else volunteers.

Alex McDonald

unread,
Jun 27, 2016, 5:31:07 PM6/27/16
to
On 27/06/16 17:12, Anton Ertl wrote:
> Alex McDonald <al...@rivadpm.com> writes:
> [Quotations RfD]
>> I'm still here. For many reasons, I'm unable to take it forward right
>> now, but if anyone else would like to do so, I would welcome it.
>
> I'll jump in, unless someone else volunteers.

Thank you.

>
> - anton
>

Brad Eckert

unread,
Jun 27, 2016, 8:45:03 PM6/27/16
to
On Friday, June 24, 2016 at 10:37:42 PM UTC-7, Anton Ertl wrote:
> Because we have automatic scoping of locals, we have more information
> to manage than can easily fit in a cell, so we use a separate leave
> stack. To determine which leave stack item belongs to which DO, we
> check whether the address of the LEAVE is between the DO and the LOOP
> we currently want to resolve (i.e., similar to option 2 above).
>
Would it work for DO to push 0 onto the leave stack and have LOOP only rake the LEAVEs until 0 is encountered?

Anton Ertl

unread,
Jun 28, 2016, 2:15:29 AM6/28/16
to
Yes, that would also be an option.
0 new messages