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

clarification on EXECUTE and return stack

175 views
Skip to first unread message

Krishna Myneni

unread,
Jun 10, 2021, 8:36:26 AM6/10/21
to
I notice that the Forth-2012 standard does not indicate that EXECUTE
does not specify that something may be placed on the return stack while
the xt is being executed. Is an implementation of EXECUTE which pushes
and pops nest-sys onto the return stack considered to be standard? The
net stack effects are still

( a -- ) ( R: -- )

The particular code which has difficulty when EXECUTE uses the return
stack is

: test ['] I 10 0 do dup execute . loop drop cr ;

This code actually "works" on Gforth in the sense that it prints the
running loop index:

test 0 1 2 3 4 5 6 7 8 9
ok

However, under kForth, it does the following:

test
10 10 10 10 10 10 10 10 10 10
ok

This behavior occurs because EXECUTE has pushed a return address onto
the return stack, pushing the loop index further down on the return
stack, while the xt for I is executing.

Krishna

Krishna Myneni

unread,
Jun 10, 2021, 8:39:25 AM6/10/21
to
On 6/10/21 7:36 AM, Krishna Myneni wrote:
> I notice that the Forth-2012 standard does not indicate that EXECUTE
> does not specify that something may be placed on the return stack while
> the xt is being executed.

Malformed sentence. It should be,

I notice that the Forth-2012 standard does not specify that EXECUTE may
place something on the return stack while the xt is being executed.

KM


Coos Haak

unread,
Jun 10, 2021, 9:51:44 AM6/10/21
to
Op Thu, 10 Jun 2021 07:39:23 -0500 schreef Krishna Myneni:
There is more to be aware of: there are implementations
that implement I and R@ differently and some the same.

Compare the result of
: test ['] i 10 0 do dup execute . loop drop cr ;
to
: two ['] r@ 10 0 do dup execute . loop drop cr ;

groet Coos

Ruvim

unread,
Jun 10, 2021, 9:53:35 AM6/10/21
to
On 2021-06-10 15:36, Krishna Myneni wrote:

> Is an implementation of EXECUTE which pushes
> and pops nest-sys onto the return stack considered to be standard?

Yes, they are standard.

> The net stack effects are still
>
> ( a -- ) ( R: -- )
>
> The particular code which has difficulty when EXECUTE uses the return
> stack is
>
> : test ['] I 10 0 do dup execute . loop drop cr ;

This code is non standard.

An ambiguous condition exists if a program tries to obtain the execution
token of a definition with undefined interpretation semantics.

Interpretation semantics for "I" are undefined by the standard. So this
code involves an ambiguous conditions, and then it's cannot be a part of
a standard program.


A Forth system implementation may be tested for compliance by standard
programs only.


--
Ruvim

Anton Ertl

unread,
Jun 10, 2021, 12:47:08 PM6/10/21
to
Krishna Myneni <krishna...@ccreweb.org> writes:
>I notice that the Forth-2012 standard does not indicate that EXECUTE
>does not specify that something may be placed on the return stack while
>the xt is being executed. Is an implementation of EXECUTE which pushes
>and pops nest-sys onto the return stack considered to be standard?

I assume you mean as in: EXECUTE pushes a nest-sys, performs the xt,
then pops nest-sys.

As Ruvim notes, the standard undefines interpretation semantics for
words that deal with the return stack, and as a consequence a standard
program cannot tick or FIND these words. So can a standard program
get at the xt of such a word? If not, you can implement EXECUTE in
such a way.

The only possible way I see is through NAME>COMPILE. That's not
guaranteed to produce an xt for performing >R, but if it does, you
should be able to EXECUTE it.

If you can get at the xt, then EXECUTE must not push nest-sys or the
system must be designed such that it works around these pushes.

E.g., you could implement >R to first pop the nest-sys, push the TOS
to the return stack and then push the nest-sys. This is what VFX is
doing.

>The particular code which has difficulty when EXECUTE uses the return
>stack is
>
>: test ['] I 10 0 do dup execute . loop drop cr ;
>
>This code actually "works" on Gforth in the sense that it prints the
>running loop index:
>
>test 0 1 2 3 4 5 6 7 8 9
> ok
>
>However, under kForth, it does the following:
>
>test
>10 10 10 10 10 10 10 10 10 10
> ok

In vfx 4.71 it works:

: test ['] I 10 0 do dup execute . loop drop cr ; test

outputs

0 1 2 3 4 5 6 7 8 9

In VFX64, it does not work, because DO...LOOP now uses registers, but
the EXECUTEd code for I still accesses the return stack (the COMPILE,d
code of course accesses the register).

- 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 2021: https://euro.theforth.net/2021

Krishna Myneni

unread,
Jun 10, 2021, 8:21:44 PM6/10/21
to
Under kForth, I think TWO is fetching the return address pushed by EXECUTE.


: test2 ['] r@ 10 0 do dup execute . loop drop cr ;
ok
test2
94256083369999 94256083369999 94256083369999 94256083369999
94256083369999 94256083369999 94256083369999 94256083369999
94256083369999 94256083369999
ok
' r@ .
94256083103672 ok

Krishna

Krishna Myneni

unread,
Jun 10, 2021, 8:22:57 PM6/10/21
to
Thanks. It would be useful for the standard to say something about use
of the return stack by EXECUTE .

Krishna


Krishna Myneni

unread,
Jun 10, 2021, 8:33:31 PM6/10/21
to
On 6/10/21 10:49 AM, Anton Ertl wrote:
> Krishna Myneni <krishna...@ccreweb.org> writes:
>> I notice that the Forth-2012 standard does not indicate that EXECUTE
>> does not specify that something may be placed on the return stack while
>> the xt is being executed. Is an implementation of EXECUTE which pushes
>> and pops nest-sys onto the return stack considered to be standard?
>
> I assume you mean as in: EXECUTE pushes a nest-sys, performs the xt,
> then pops nest-sys.
>

That's what I meant, but in the actual code, it's a bit more
complicated. EXECUTE pushes a nest-sys and sets the instruction pointer
so that the VM will perform xt on NEXT. The virtual machine pops the
nest-sys when the code referenced by xt returns.

> ...
> If you can get at the xt, then EXECUTE must not push nest-sys or the
> system must be designed such that it works around these pushes.
>

This is the problem. I can get the xt for I , but EXECUTE pushes
nest-sys and DO and LOOP make use of the return stack.

> E.g., you could implement >R to first pop the nest-sys, push the TOS
> to the return stack and then push the nest-sys. This is what VFX is
> doing.
>

Ok. That might work.

Krishna



Ruvim

unread,
Jun 11, 2021, 3:40:08 AM6/11/21
to
On 2021-06-10 18:49, Anton Ertl wrote:
> Krishna Myneni <krishna...@ccreweb.org> writes:
>> I notice that the Forth-2012 standard does not indicate that EXECUTE
>> does not specify that something may be placed on the return stack while
>> the xt is being executed. Is an implementation of EXECUTE which pushes
>> and pops nest-sys onto the return stack considered to be standard?
>
> I assume you mean as in: EXECUTE pushes a nest-sys, performs the xt,
> then pops nest-sys.
>
> As Ruvim notes, the standard undefines interpretation semantics for
> words that deal with the return stack, and as a consequence a standard
> program cannot tick or FIND these words.

More neatly, a standard program cannot use "FIND" to obtain the
execution token of such a word.

But it can use "FIND" to obtain xt of a definition that serves to
perform the interpretation or compilation semantics for such a word.
This xt just cannot be considered as an xt that identifies the execution
semantics of the argument of "FIND" (for the words with non default
interpretation semantics).

Certainly, a standard program cannot perform interpretation semantics
for the words with undefined interpretation semantics.


> So can a standard program
> get at the xt of such a word? If not, you can implement EXECUTE in
> such a way.

My conclusion that a standard program cannot get xt of such a word, i.e.
an xt that identifies execution semantics of this word (a word with non
default interpretation semantics).



> The only possible way I see is through NAME>COMPILE. That's not
> guaranteed to produce an xt for performing >R, but if it does, you
> should be able to EXECUTE it.

It seems, you meant "NAME>INTERPRET". But it doesn't return the
execution token that identifies execution semantics for a word in the
argument.

The returned xt "represents the interpretation semantics" for a word in
the argument. It isn't enough precisely formulated. But the idea is that
performing xt performs the interpretation semantics for the word in the
argument.


A problem is that a standard program cannot perform interpretation
semantics for a word with undefined interpretation semantics.

Even via "NAME>INTERPRET", this behavior cannot be tested by a standard
program. It can be any implementation-defined behavior.

For example, the following code is non standard

: ?name>interpret ( nt -- xt )
dup 0= -13 and throw
name>interpret
dup 0= -14 and throw
;

">r" find-name ?name>interpret value interp(>r)

: >r_v2 interp(>r) execute ;

\ The behavior of ">r_v2" cannot be concluded form the standard.
\ And so, it cannot be tested by a standard program.
\ And then, it may show any behavior.


In some plausible system ">r_v2" shows the expected behavior. But in
another plausible system ">r_v2" throws an exception.


> If you can get at the xt, then EXECUTE must not push nest-sys or the
> system must be designed such that it works around these pushes.

It would restrict implementations, but a standard program cannot get
such xt.


--
Ruvim

Anton Ertl

unread,
Jun 11, 2021, 4:48:05 AM6/11/21
to
Krishna Myneni <krishna...@ccreweb.org> writes:
>On 6/10/21 10:49 AM, Anton Ertl wrote:
>> Krishna Myneni <krishna...@ccreweb.org> writes:
>>> I notice that the Forth-2012 standard does not indicate that EXECUTE
>>> does not specify that something may be placed on the return stack while
>>> the xt is being executed. Is an implementation of EXECUTE which pushes
>>> and pops nest-sys onto the return stack considered to be standard?
>>
>> I assume you mean as in: EXECUTE pushes a nest-sys, performs the xt,
>> then pops nest-sys.
>>
>
>That's what I meant, but in the actual code, it's a bit more
>complicated. EXECUTE pushes a nest-sys and sets the instruction pointer
>so that the VM will perform xt on NEXT. The virtual machine pops the
>nest-sys when the code referenced by xt returns.

The typical threaded-code approach (used, e.g., in Gforth) is to leave
the Forth IP alone, set W to the xt and then do a machine-level jump
to the code address of xt. If that code address corresponds to a
primitive, it performs it and then continues with the next word; if
that code address corresponds to a colon definition, the code address
is that of docol, and docol will push IP, set IP to the threaded code
associated with the xt in W, and run that. For other kinds of words
(e.g. variables, constants, they find their body through the xt in W.

With that design, there is no need for EXECUTE to push nest-sys
itself.

>> E.g., you could implement >R to first pop the nest-sys, push the TOS
>> to the return stack and then push the nest-sys. This is what VFX is
>> doing.
>>
>
>Ok. That might work.

If you don't have a Forth IP separate from the machine PC, this seems
to be the best approach to me. Note that if the way you perform
COMPILE,d code does not push a nest-sys, you need to COMPILE,
different code than what you EXECUTE.

Anton Ertl

unread,
Jun 11, 2021, 6:23:21 AM6/11/21
to
Ruvim <ruvim...@gmail.com> writes:
>On 2021-06-10 18:49, Anton Ertl wrote:
>> As Ruvim notes, the standard undefines interpretation semantics for
>> words that deal with the return stack, and as a consequence a standard
>> program cannot tick or FIND these words.
>
>More neatly, a standard program cannot use "FIND" to obtain the
>execution token of such a word.
>
>But it can use "FIND" to obtain xt of a definition that serves to
>perform the interpretation or compilation semantics for such a word.

If one of our "Clarify FIND" proposals is accepted, yes. But in
Forth-94 and Forth-2012, it's an ambiguous condition:

|4.1.2 Ambiguous conditions
|
|attempting to obtain the execution token, (e.g., with 6.1.0070 ',
|6.1.1550 FIND, etc. of a definition with undefined interpretation
|semantics;

>> The only possible way I see is through NAME>COMPILE. That's not
>> guaranteed to produce an xt for performing >R, but if it does, you
>> should be able to EXECUTE it.
>
>It seems, you meant "NAME>INTERPRET".

No, I meant NAME>COMPILE. E.g., in Gforth

s" >r" find-name name>compile

produces xt1 xt2, where xt1 EXECUTE performs >R and xt2 EXECUTE
performs COMPILE,. You might argue that a standard program cannot
know this, but I think that a standard program can test if xt2 EXECUTE
behaves like COMPILE, and in that case xt1 must represent the
execution semantics of >R.

NAME>INTERPRET may return 0 for the nt of >R, that's why I did not
mean NAME>INTERPRET.

Krishna Myneni

unread,
Jun 11, 2021, 8:11:23 AM6/11/21
to
I think we are running into the conflict between Forth designed for
resource-constrained systems (micro-controllers and similar processors)
vs Forth designed for resource-rich systems (SBCs and desktops). For the
specific problem with ticking I and J, the underlying problem is that DO
and LOOP are often implemented using the return stack. It doesn't
require significant resources to provide a separate stack for such
words, and I think that's the solution to this specific problem, rather
than using return stack tricks.

Similarly, there is probably little need to implement a Forth which uses
the data stack as the control stack on most targets. If we have arrived
at a point at which we can do away with such allowances, that would go a
long way to improving the consistency of Forth words, with regard to '
['] EXECUTE etc., as well as greater allowances in coding. A
particularly obnoxious restriction, in my view, is the allowance to push
control information onto the data stack when beginning a colon
definition. Access to items on the stack, for use by the definition, e.g.

variable a
a : fetch-a literal @ ;

can't be standard code because the data stack is used on some systems as
the control stack.

Krishna



Anton Ertl

unread,
Jun 11, 2021, 8:47:33 AM6/11/21
to
Krishna Myneni <krishna...@ccreweb.org> writes:
>I think we are running into the conflict between Forth designed for
>resource-constrained systems (micro-controllers and similar processors)
>vs Forth designed for resource-rich systems (SBCs and desktops). For the
>specific problem with ticking I and J, the underlying problem is that DO
>and LOOP are often implemented using the return stack. It doesn't
>require significant resources to provide a separate stack for such
>words, and I think that's the solution to this specific problem, rather
>than using return stack tricks.

You can support ticking I and J, and even ticking >R etc. in this way.
But note that both Gforth and VFX 4.71 use the same stack for return
addresses, >R etc., and I and J, and your test works on them. So you
do not need an extra stack for making it work, and it's not a conflict
between Forth systems designed for resource-constrained and
resource-rich platforms. It's just the question of whether you are
willing to make it work.

>Similarly, there is probably little need to implement a Forth which uses
>the data stack as the control stack on most targets. If we have arrived
>at a point at which we can do away with such allowances, that would go a
>long way to improving the consistency of Forth words, with regard to '
>['] EXECUTE etc., as well as greater allowances in coding. A
>particularly obnoxious restriction, in my view, is the allowance to push
>control information onto the data stack when beginning a colon
>definition. Access to items on the stack, for use by the definition, e.g.
>
>variable a
>a : fetch-a literal @ ;
>
>can't be standard code because the data stack is used on some systems as
>the control stack.

Not a good example. Here's a standard way to achieve the same:

variable a
: fetch-a [ a ] literal @ ;

But sure, something like

here 0 ,
>r : foo [ r@ r> ] literal @ 1 literal +! ;

would require more changes to become standard Forth, maybe

here pad ! 0 ,
: foo [ pad @ dup ] literal @ 1 literal +! ;

All somewhat cumbersome.

Ruvim

unread,
Jun 11, 2021, 2:55:40 PM6/11/21
to
On 2021-06-11 12:57, Anton Ertl wrote:
> Ruvim <ruvim...@gmail.com> writes:
>> On 2021-06-10 18:49, Anton Ertl wrote:
>>> As Ruvim notes, the standard undefines interpretation semantics for
>>> words that deal with the return stack, and as a consequence a standard
>>> program cannot tick or FIND these words.
>>
>> More neatly, a standard program cannot use "FIND" to obtain the
>> execution token of such a word.
>>
>> But it can use "FIND" to obtain xt of a definition that serves to
>> perform the interpretation or compilation semantics for such a word.
>
> If one of our "Clarify FIND" proposals is accepted, yes. But in
> Forth-94 and Forth-2012, it's an ambiguous condition:
>
> |4.1.2 Ambiguous conditions
> |
> |attempting to obtain the execution token, (e.g., with 6.1.0070 ',
> |6.1.1550 FIND, etc. of a definition with undefined interpretation
> |semantics;


Well, but "FIND" may be applied to any string, isn't it?

So, if a program applies "FIND" to some string, does it mean that the
program attempts to obtain the execution token of the corresponding
named definition? (1)


A problem is that the spec says that "FIND" returns "its execution
token", i.e. the execution token *of* the found definition. Also it says
that "FIND" may return the different values depending on state. In this
context, the different xt means that they identify the different ES. But
a definition may have not more than one ES. Hence, the specification for
"FIND" contradicts itself.

The parts "its execution token" and "the values [...] may differ" are
mutually exclusive. If one of them is true, another is false.

From a contradict formula, one can infer both some proposition and its
negation. So the answer to the question (1) cannot rely on the
contradict specification for "FIND".




>>> The only possible way I see is through NAME>COMPILE. That's not
>>> guaranteed to produce an xt for performing >R, but if it does, you
>>> should be able to EXECUTE it.
>>
>> It seems, you meant "NAME>INTERPRET".
>
> No, I meant NAME>COMPILE. E.g., in Gforth
>
> s" >r" find-name name>compile
>
> produces xt1 xt2, where xt1 EXECUTE performs >R and xt2 EXECUTE
> performs COMPILE,. You might argue that a standard program cannot
> know this, but I think that a standard program can test if xt2 EXECUTE
> behaves like COMPILE, and in that case xt1 must represent the
> execution semantics of >R.


The mentioned clause from 4.1.2 indicates an open list of methods to
obtain an execution token. It doesn't matter what particular method is used.

So, if a program consider xt1 as the execution token for ">r" then this
program involves an ambiguous condition.

A standard program cannot consider xt1 as execution token for ">r".



> NAME>INTERPRET may return 0 for the nt of >R, that's why I did not
> mean NAME>INTERPRET.

It seems to me, testing this result for 0 is not worse than testing that
xt2 behaves like "COMPILE,".



--
Ruvim

Ruvim

unread,
Jun 12, 2021, 4:25:48 AM6/12/21
to
On 2021-06-11 21:55, Ruvim wrote:
> On 2021-06-11 12:57, Anton Ertl wrote:

>> |4.1.2 Ambiguous conditions
>> |
>> |attempting to obtain the execution token, (e.g., with 6.1.0070 ',
>> |6.1.1550 FIND, etc. of a definition with undefined interpretation
>> |semantics;
[...]

>>>> The only possible way I see is through NAME>COMPILE.  That's not
>>>> guaranteed to produce an xt for performing >R, but if it does, you
>>>> should be able to EXECUTE it.
>>>
>>> It seems, you meant "NAME>INTERPRET".
>>
>> No, I meant NAME>COMPILE.  E.g., in Gforth
>>
>> s" >r" find-name name>compile
>>
>> produces xt1 xt2, where xt1 EXECUTE performs >R and xt2 EXECUTE
>> performs COMPILE,.  You might argue that a standard program cannot
>> know this, but I think that a standard program can test if xt2 EXECUTE
>> behaves like COMPILE,

BTW, how a program can test this? (except compare xt2 with xt of
"compile,", that is not robust)


>> and in that case xt1 must represent the execution semantics of >R.
>
>
> The mentioned clause from 4.1.2 indicates an open list of methods to
> obtain an execution token. It doesn't matter what particular method is
> used.
>
> So, if a program consider xt1 as the execution token for ">r" then this
> program involves an ambiguous condition.
>
> A standard program cannot consider xt1 as execution token for ">r".
>


Yet another question.

If we assume your clarification for "EXECUTE", or my equivalence for
"EXECUTE", then "EXECUTE" cannot be applied to xt1.

Then, you cannot check whether xt1 identifies execution semantics for ">r".

If a Forth system defines ">r" and "compile," in the following way:

: >r, postpone >r ;
: >r -14 throw ;
: compile, ( xt -- )
dup ['] >r = if drop >r, exit then compile,
;

t{ ">r" find-name name>compile -> ' >r ' compile, }t

Does the execution token of this ">r" word identifies execution
semantics for the standard ">r" word?


My position is that (from a program point of view) xt1 is the execution
token of an internal definition that serves to perform the compilation
semantics for the ">r" word, and nothing more.

So, even if xt2 is the execution token of "compile," a program still
cannot use xt1 as the execution token of ">r" word.

Krishna Myneni

unread,
Jun 14, 2021, 8:36:44 AM6/14/21
to
Here's a better example, from a recent post of mine:

: LT_P ( F: a b "name" -- )
: ( F: x -- x' )
fswap postpone fliteral postpone f*
postpone fliteral postpone f+ postpone ; ;

This works for a separate fp stack system (now standardized in
Forth-2012), regardless of whether or not the data stack is used as the
control stack during a definition. However, if we make an integer
version of the above,

: LT_Pi ( a b "name" -- )
: ( n1 -- n2 )
swap postpone literal postpone *
postpone literal postpone + postpone ; ;

the word LT_Pi (integer version of the linear transformation defining
word using POSTPONE) the word will likely fail on execution, on Forth
systems which use the data stack as the control stack.

Tests in gforth and kforth64:

\ gforth (0.7.9.x)
\ ---------------

3e0 2e0 LT_P lt1 ok
6e0 lt1 f. 20. ok

3 2 LT_Pi lt2
*the terminal*:12:11: error: Control structure mismatch
3 2 LT_Pi >>>lt2<<<
Backtrace:
kernel/cond.fs:113:26: 0 $7F3F6E2E4CD8 throw
glocals.fs:631:5: 1 $7F3F6E2F6610 ?struc
kernel/comp.fs:768:5: 2 $7F3F6E2DB7C8 ;-hook
*terminal*:11:44: 3 $7F3F6E34F160 name-compsem


\ kforth64 (0.2.x)
\ -----------------

3e0 2e0 LT_P lt1
ok
6e0 lt1 f.
20 ok

3 2 LT_Pi lt2
ok
6 lt2 .
20 ok

The direct translation of the floating point version of LT_P to an
integer version cannot be guaranteed to work on standard systems due to
the allowance for the control stack to be the data stack.

The Forth (94 and 2012) standards provide an abstracted interface for
the control stack which is implementation independent. The only reason I
can see then to allow the data stack to be used for the control stack is
for severely resource-constrained systems. If resource constraints are
no longer a valid reason, then problems like the above can be avoided
simply by implementing a separate control stack.


> But sure, something like
>
> here 0 ,
>> r : foo [ r@ r> ] literal @ 1 literal +! ;
>
> would require more changes to become standard Forth, maybe
>
> here pad ! 0 ,
> : foo [ pad @ dup ] literal @ 1 literal +! ;
>
> All somewhat cumbersome.
>

Yes, your examples above are cumbersome, and the gymnastics with return
stack manipulation or global memory areas can be avoided if the data
stack is not used as the control stack.

Krishna


none albert

unread,
Jun 14, 2021, 9:43:01 AM6/14/21
to
In article <s9vjta$sip$1...@dont-email.me>,
Krishna Myneni <krishna...@ccreweb.org> wrote:
>I think we are running into the conflict between Forth designed for
>resource-constrained systems (micro-controllers and similar processors)
>vs Forth designed for resource-rich systems (SBCs and desktops). For the
>specific problem with ticking I and J, the underlying problem is that DO
>and LOOP are often implemented using the return stack. It doesn't
>require significant resources to provide a separate stack for such
>words, and I think that's the solution to this specific problem, rather
>than using return stack tricks.

With a resource restricted system I mean a system with a couple of K flash
and 128 byte ram. Stack can only be in ram. An extra stack is prohibitive.
<SNIP>
>
>can't be standard code because the data stack is used on some systems as
>the control stack.
Unless you want to implement a STATE-less number/literal handling
a separate control stack has not much merit, so yes.

>
>Krishna
>
>
>
--
"in our communism country Viet Nam, people are forced to be
alive and in the western country like US, people are free to
die from Covid 19 lol" duc ha
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

dxforth

unread,
Jun 14, 2021, 10:23:46 AM6/14/21
to
On 14/06/2021 22:36, Krishna Myneni wrote:
> ...
>
> \ kforth64 (0.2.x)
> \ -----------------
>
> 3e0 2e0 LT_P lt1
> ok
> 6e0 lt1 f.
> 20 ok
>
> 3 2 LT_Pi lt2
> ok
> 6 lt2 .
> 20 ok
>

SwiftForth i386-Win32 3.11.1 31-Mar-2021

: LT_Pi ( a b "name" -- )
-balance : ( n1 -- n2 )
swap postpone literal postpone *
postpone literal postpone + postpone ;
+balance ;

dxforth

unread,
Jun 14, 2021, 11:04:26 AM6/14/21
to
It appears SwiftForth doesn't do a CSP check so the above will work
regardless of +/-BALANCE


Marcel Hendrix

unread,
Jun 15, 2021, 2:33:35 AM6/15/21
to
On Monday, June 14, 2021 at 2:36:44 PM UTC+2, Krishna Myneni wrote:
> On 6/11/21 7:32 AM, Anton Ertl wrote:
[..]
> Here's a better example, from a recent post of mine:
>
> : LT_P ( F: a b "name" -- )
> : ( F: x -- x' )
> fswap postpone fliteral postpone f*
> postpone fliteral postpone f+ postpone ; ;
[..]
> : LT_Pi ( a b "name" -- )
> : ( n1 -- n2 )
> swap postpone literal postpone *
> postpone literal postpone + postpone ; ;
>
> the word LT_Pi (integer version of the linear transformation defining
> word using POSTPONE) the word will likely fail on execution, on Forth
> systems which use the data stack as the control stack.
[..]
> The Forth (94 and 2012) standards provide an abstracted interface for
> the control stack which is implementation independent. The only reason I
> can see then to allow the data stack to be used for the control stack is
> for severely resource-constrained systems. If resource constraints are
> no longer a valid reason, then problems like the above can be avoided
> simply by implementing a separate control stack.

That is not the only way to do it.

[1] iForth x64 server 1.32 (console), Apr 27 2021, 17:25:38.
[2] Stuffed iForth at $0109C7E0 [entry: $01100000]
[3] Having a Windows terminal.
[4] Console is active.
[5] Sound devices are internal.

iForth version 6.9.104, generated 13:12:10, June 13, 2021.
x86_64 binary, native floating-point, extended precision.
Copyright 1996 - 2021 Marcel Hendrix.
[6] Use --- iForth.prf
Creating --- Locate support Version 2.01 ---
Creating --- Several utilities Version 3.53 ---
Creating --- Extended OS words Version 3.19 ---
Creating --- Terminal Driver Version 3.60 ---
Creating --- Command line Editor Version 1.36 ---
Creating --- Online help Version 1.36 ---
Creating --- Glossary Generator Version 1.05 ---
Creating --- Introspection Version 0.01 ---
Creating --- Disassembler Version 2.41 ---
FORTH> : LT_P ( F: a b "name" -- )
<3>[FORTH>] : ( F: x -- x' )
<3>[FORTH>] fswap postpone fliteral postpone f*
<3>[FORTH>] postpone fliteral postpone f+ postpone ; ; ok
FORTH> : LT_Pi ( a b "name" -- )
<3>[FORTH>] : ( n1 -- n2 )
<3>[FORTH>] swap postpone literal postpone *
<3>[FORTH>] postpone literal postpone + postpone ; ; ok
FORTH> 3e0 2e0 LT_P lt1 ok
FORTH> 6e0 lt1 f. 20.000000 ok
FORTH> 3 2 LT_Pi lt2 ok
FORTH> 6 lt2 . 20 ok

-marcel

Ruvim

unread,
Jun 15, 2021, 4:33:05 AM6/15/21
to
[...]
> FORTH> : LT_P ( F: a b "name" -- )
> <3>[FORTH>] : ( F: x -- x' )
> <3>[FORTH>] fswap postpone fliteral postpone f*
> <3>[FORTH>] postpone fliteral postpone f+ postpone ; ; ok
> FORTH> : LT_Pi ( a b "name" -- )
> <3>[FORTH>] : ( n1 -- n2 )
> <3>[FORTH>] swap postpone literal postpone *
> <3>[FORTH>] postpone literal postpone + postpone ; ; ok
> FORTH> 3e0 2e0 LT_P lt1 ok
> FORTH> 6e0 lt1 f. 20.000000 ok
> FORTH> 3 2 LT_Pi lt2 ok
> FORTH> 6 lt2 . 20 ok


Do you mean that the colon-sys size is 0 in iForth?
Then it doesn't solve the problem, but only one particular case.

Otherwise, what do you mean by other ways?


--
Ruvim

dxforth

unread,
Jun 15, 2021, 6:29:55 AM6/15/21
to
>r >r : r> postpone literal postpone *
r> postpone literal postpone + postpone ; ;

A professional adapts to any situation. Is computing different
from other professions?

none albert

unread,
Jun 15, 2021, 7:16:43 AM6/15/21
to
In article <sa7igq$ji4$1...@dont-email.me>,
Krishna Myneni <krishna...@ccreweb.org> wrote:
<SNIP>
>The Forth (94 and 2012) standards provide an abstracted interface for
>the control stack which is implementation independent. The only reason I
>can see then to allow the data stack to be used for the control stack is
>for severely resource-constrained systems. If resource constraints are
>no longer a valid reason, then problems like the above can be avoided
>simply by implementing a separate control stack.

With the whole swap space (say 500 gByte) available for the dictionary
ciforth hardly counts as a resource-contrained system.

I have no separate control stack to avoid superfluous complexity in ciforth.
Does that count for nothing?

<SNIP>
>Krishna
>
Groetjes Albert

Krishna Myneni

unread,
Jun 15, 2021, 8:01:41 AM6/15/21
to
Your version appears to be standards-compatible. It is also asymmetric
with the standards-compatible floating point definition. The general
difficulty of passing parameters to a colon definition plus the
asymmetry between the floating point version and the integer version,
plus the fact that we do not have to use the return stack to pass
parameters on multiple Forth systems (as you demonstrated) begs the
question: can we make things easier for the Forth programmer by
sacrificing an archaic allowance?

Krishna

Krishna Myneni

unread,
Jun 15, 2021, 8:08:25 AM6/15/21
to
On 6/15/21 6:16 AM, albert wrote:
> In article <sa7igq$ji4$1...@dont-email.me>,
> Krishna Myneni <krishna...@ccreweb.org> wrote:
> <SNIP>
>> The Forth (94 and 2012) standards provide an abstracted interface for
>> the control stack which is implementation independent. The only reason I
>> can see then to allow the data stack to be used for the control stack is
>> for severely resource-constrained systems. If resource constraints are
>> no longer a valid reason, then problems like the above can be avoided
>> simply by implementing a separate control stack.
>
> With the whole swap space (say 500 gByte) available for the dictionary
> ciforth hardly counts as a resource-contrained system.
>
> I have no separate control stack to avoid superfluous complexity in ciforth.
> Does that count for nothing?
>

The choice is between trading off complexity in the Forth system versus
allowing Forth coding easier and more logically consistent for the Forth
programmer. Generally, I would opt for the latter, particularly when the
system complexity increase is negligible. I do not consider removing the
allowance for using the data stack as a control stack to be superfluous
complexity -- reserving memory and adding push, pop, and clear functions
for the stack should be trivial in systems which aren't so severely
restricted as having 128 bytes of RAM.

Krishna

Marcel Hendrix

unread,
Jun 15, 2021, 1:47:24 PM6/15/21
to
No, what happens here is that colon-sys was moved out of the
way, because it is well-known to iForth -- either from analysis
of Forth code over the past 40 years, or from personal experience
of its author -- that there are a number of useful cases where not
moving the colon-sys limits useability.

> Then it doesn't solve the problem, but only one particular case.

Practically speaking, only until it is found that the other cases
are useful.

> Otherwise, what do you mean by other ways?

I was only trying to say that the example assumed certain
implementation practices and is no proof that a separate
control stack is needed.

-marcel

Krishna Myneni

unread,
Jun 22, 2021, 12:06:33 AM6/22/21
to
On 6/11/21 7:32 AM, Anton Ertl wrote:
> Krishna Myneni <krishna...@ccreweb.org> writes:

>> ... A
>> particularly obnoxious restriction, in my view, is the allowance to push
>> control information onto the data stack when beginning a colon
>> definition. Access to items on the stack, for use by the definition, e.g.
>>
>> variable a
>> a : fetch-a literal @ ;
>>
>> can't be standard code because the data stack is used on some systems as
>> the control stack.
>
> Not a good example. Here's a standard way to achieve the same:
>

And here's another example of what can be done if the data stack is not
used as a control stack at the beginning of a colon definition. This one
is from Robert Spykerman's sudoku puzzle solver.

original code:
-----------
\ ie x y -- ; adds x into bitmap y
: addbits_row 1 rot lshift swap cells sudoku_row + dup @ rot or swap ! ;
: addbits_col 1 rot lshift swap cells sudoku_col + dup @ rot or swap ! ;
: addbits_box 1 rot lshift swap cells sudoku_box + dup @ rot or swap ! ;
-----------

The above definitions use almost the same code with just one different
symbol. It can be rewritten as follows when a parameter on the data
stack is not masked by the start of a definition.

new code:
---------
\ ie x y -- ; adds x into bitmap y
:noname ( ie x y a -- ) >r 1 rot lshift swap cells r> + dup @ rot or
swap ! ;
dup : addbits_row sudoku_row literal execute ;
dup : addbits_col sudoku_col literal execute ;
: addbits_box sudoku_box literal execute ;
---------

The code in the anonymous definition is nearly a direct copy of the
repeated code in the original definitions.

Granted this example is really an example of a missed factoring
opportunity -- one can give a meaningful name to the :NONAME definition,
and, in this instance, it would make sense to define a word such as
ADDBITS with the same code as the :NONAME definition, and then define
ADDBITS_ROW , ADDBITS_COL , and ADDBITS_BOX using ADDBITS. However, one
may expect instances where an anonymous definition is appropriate to
carry into the definition of multiple words. Leaving the data stack
unmasked for definitions then makes it easy.

Krishna



Krishna Myneni

unread,
Jun 22, 2021, 7:56:48 AM6/22/21
to
On 6/21/21 11:06 PM, Krishna Myneni wrote:
...
> And here's another example of what can be done if the data stack is not
> used as a control stack at the beginning of a colon definition. This one
> is from Robert Spykerman's sudoku puzzle solver.
>
> original code:
> -----------
> \ ie x y --   ;  adds x into bitmap y
> : addbits_row 1 rot lshift swap cells sudoku_row + dup @ rot or swap ! ;
> : addbits_col 1 rot lshift swap cells sudoku_col + dup @ rot or swap ! ;
> : addbits_box 1 rot lshift swap cells sudoku_box + dup @ rot or swap ! ;
> -----------
>
> The above definitions use almost the same code with just one different
> symbol. It can be rewritten as follows when a parameter on the data
> stack is not masked by the start of a definition.
>
> new code:
> ---------
> \ ie x y --   ;  adds x into bitmap y
> :noname ( ie x y a -- ) >r 1 rot lshift swap cells r> + dup @ rot or
> swap ! ;
> dup  : addbits_row sudoku_row literal execute ;
> dup  : addbits_col sudoku_col literal execute ;
>      : addbits_box sudoku_box literal execute ;
> ---------
...
> Granted this example is really an example of a missed factoring
> opportunity ... However, one
> may expect instances where an anonymous definition is appropriate to
> carry into the definition of multiple words. ...

Also, it should be possible to write the above even more simply:

\ ie x y -- ; adds x into bitmap y
:noname ( ie x y a -- ) >r 1 rot lshift swap cells r> + dup @ rot or
swap ! ;
dup : addbits_row sudoku_row [ compile, ] ;
dup : addbits_col sudoku_col [ compile, ] ;
: addbits_box sudoku_box [ compile, ] ;


To write the above COMPILE, needs to be allowed to compile code into the
current definition, from interpretation state.

Forth system implementations should strive to avoid throwing up
roadblocks to programmers when the meaning of the code is not ambiguous.

Krishna

dxforth

unread,
Jun 22, 2021, 9:07:51 PM6/22/21
to
Simple would be naming the :noname and all the machinations go away.

Regarding COMPILE, inside [ ] it's a rare occurrence AFAICS and can be
handled with LITERAL EXECUTE - something quotations fans would know about.
I'm not against interpreted use of COMPILE, but don't see it as a game-
changer. If inefficiency and waste in standard programs is of concern,
I'd be looking at everyday things like ANS' ENDOF and 200x' quotations
and recognizers :)
0 new messages