Discussion:
Juggling system-compilation items
(too old to reply)
Ruvim
2024-08-09 14:05:47 UTC
Permalink
Do you know a Forth system in which the following definition for "const"
is compiled but does not work as expected?


: const ( x "<spaces>name" -- )
depth >r ( x ) ( R: n.depth )
: ( x colon-sys ) ( R: n.depth )
depth r> - ( x colon-sys n.size ) ( R: )
n>r ( x ) ( R: i*x n.size )
postpone literal ( ) ( R: i*x n.size )
nr> ( colon-sys n.size ) ( R: )
drop ( colon-sys )
postpone ; ( )
;


t{ 123 const foo -> }t
t{ foo -> 3 }t


Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>


--
Ruvim
PMF
2024-08-10 08:57:04 UTC
Permalink
Post by Ruvim
Do you know a Forth system in which the following definition for "const"
is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
depth >r ( x ) ( R: n.depth )
: ( x colon-sys ) ( R: n.depth )
depth r> - ( x colon-sys n.size ) ( R: )
n>r ( x ) ( R: i*x n.size )
postpone literal ( ) ( R: i*x n.size )
nr> ( colon-sys n.size ) ( R: )
drop ( colon-sys )
postpone ; ( )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>
--
Ruvim
Yes if fails on both my systems lxf and lxf64!
the reason if fails is that : stores the current depth and ; later
compares it with the actual
at that point. This is to catch unmatched loops and conditionals.
The usual use of >r r> works as intended

: const >r : r> postpone literal postpone ; ;

I think !csp and ?csp are common also in other systems. I certainly did
not invent them.

BR
Peter
Ruvim
2024-08-10 23:17:31 UTC
Permalink
Post by PMF
Post by Ruvim
Do you know a Forth system in which the following definition for "const"
is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
   depth >r          ( x )                   ( R: n.depth )
   :                 ( x colon-sys )         ( R: n.depth )
   depth r> -        ( x colon-sys n.size )  ( R: )
   n>r               ( x )                   ( R: i*x n.size )
   postpone literal  (   )                   ( R: i*x n.size )
   nr>               ( colon-sys n.size )    ( R: )
   drop              ( colon-sys )
   postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>
--
Ruvim
Yes if fails on both my systems lxf and lxf64!
the reason if fails is that : stores the current depth and ; later
compares it with the actual
at that point. This is to catch unmatched loops and conditionals.
The usual use of >r r> works as intended
: const >r : r> postpone literal postpone ; ;
Yes, my definition can be implemented simpler, but it is given only for
illustration and test.


Another use case is to get xt that `:noname` leaves under colon-sys
(published many times in comp.lang.forth since 2000 [1])

For example:

: rec: ( "<spaces>name" -- colon-sys )
defer depth >r :noname depth r> - 1- roll
latest-name name> defer!
;

\ Usage example
rec: fib ( u.index -- u.value )
dup 2 u< if exit then
dup 2 - fib swap 1- fib +
;

t{ 0 fib 1 fib 2 fib 3 fib 4 fib -> 0 1 1 2 3 }t


Another real-life example in [2]. Regarding `latest-name` see [3].


Another use case is to factor out a definition builder using a helper
method like this:

: build-noname-with ( i*x xt.builder -- j*x xt.new )
\ xt.builder ( i*x -- j*x )
depth >r :noname depth r> - n>r
execute
nr> drop postpone ;
;

\ Usage example
: compose-before ( xt2 xt1 -- xt3 )
[: compile, compile, ;] build-noname-with
;
: compose ( xt1 xt2 -- xt3 )
swap compose-before
;

t{ [: 1 ;] [: 2 ;] compose execute -> 1 2 }t



All such techniques are not available if the Forth system does not allow
the stack depth to be changed between `:` and `;`.

Would you like to see these techniques available to standard programs?
Post by PMF
I think !csp and ?csp are common also in other systems. I certainly did
not invent them.
Yes, it's a simple method to check the control-flow structures balance
from the FIG-Forth model.

I would suggest avoiding this method in Forth implementations.




[1] subject: colon-sys and ANS, 2000
<https://groups.google.com/g/comp.lang.forth/c/BU0sVOhxHQo/m/xJ7xXmNjV9YJ>
[2] minos2/md-viewer.fs
<https://github.com/forthy42/gforth/blob/3008f604af74aafd/minos2/md-viewer.fs#L356>
[3] [Proposal] New words: latest-name and latest-name-in
<https://forth-standard.org/proposals/new-words-latest-name-and-latest-name-in?hideDiff#reply-1249>


--
Ruvim
a***@spenarnc.xs4all.nl
2024-08-11 08:38:28 UTC
Permalink
Post by Ruvim
Post by PMF
I think !csp and ?csp are common also in other systems. I certainly did
not invent them.
Yes, it's a simple method to check the control-flow structures balance
from the FIG-Forth model.
I would suggest avoiding this method in Forth implementations.
It saved me a lot of mistakes. ciforth reports an error.
If you care to look the error up in the documentation, you can see
that you can turn this off, if you want to.
Post by Ruvim
--
Ruvim
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
Ruvim
2024-08-11 09:09:46 UTC
Permalink
Post by a***@spenarnc.xs4all.nl
Post by Ruvim
Post by PMF
I think !csp and ?csp are common also in other systems. I certainly did
not invent them.
Yes, it's a simple method to check the control-flow structures balance
from the FIG-Forth model.
I would suggest avoiding this method in Forth implementations.
It saved me a lot of mistakes. ciforth reports an error.
If you care to look the error up in the documentation, you can see
that you can turn this off, if you want to.
I don't mean removing this check. I mean using another implementation.

This check is easy to implement without being tied to stack depth.
For example:

-1023 here + constant colon-magic

: :noname ( -- xt colon-sys )
:noname colon-magic
;

: : ( "name" -- colon-sys )
: colon-magic
;

: ; ( colon-sys -- )
colon-magic <> -22 and throw
postpone ;
[ drop ] \ due to new `:` and old `;`
; immediate

: does> ( colon-sys -- colon-sys )
colon-magic <> -22 and throw
postpone does> colon-magic
; immediate



--
Ruvim
mhx
2024-08-10 09:51:51 UTC
Permalink
iForth64 does not have N>R and NR> ( never needed them ).
After pulling them from https://forth-standard.org/standard/tools/ ...

FORTH> 42 const aap ok
FORTH> words
aap const
ok
FORTH> see aap
Flags: TOKENIZE, ANSI
: aap 42 ; ok
FORTH> ' aap idis
$013414C0 : aap
$013414CA push #42 b#
$013414CC ;

No problem.

-marcel
Ruvim
2024-08-10 23:14:09 UTC
Permalink
Post by mhx
iForth64 does not have N>R and NR> ( never needed them ).
After pulling them from https://forth-standard.org/standard/tools/ ...
There is a way to implement them in a standard program, I accidentally
came across you old post:
<https://groups.google.com/g/comp.lang.forth/c/G6-M-NjRRq0/m/WkFH84TRtKwJ>
Post by mhx
FORTH> 42 const aap  ok
FORTH> words
aap                   const
ok
FORTH> see aap
Flags: TOKENIZE, ANSI
: aap  42 ;  ok
FORTH> ' aap idis
$013414C0  : aap
$013414CA  push          #42 b#
$013414CC  ;
No problem.
Thank you!



--
Ruvim
Krishna Myneni
2024-08-11 03:29:14 UTC
Permalink
Post by Ruvim
Do you know a Forth system in which the following definition for "const"
is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
  depth >r          ( x )                   ( R: n.depth )
  :                 ( x colon-sys )         ( R: n.depth )
  depth r> -        ( x colon-sys n.size )  ( R: )
  n>r               ( x )                   ( R: i*x n.size )
  postpone literal  (   )                   ( R: i*x n.size )
  nr>               ( colon-sys n.size )    ( R: )
  drop              ( colon-sys )
  postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>
--
Ruvim
In kForth, for the code above, foo returns 123 which is what I expect.

--
Krishna


=== begin code ===

: N>R \ xn .. x1 N -- ; R: -- x1 .. xn n
\ Transfer N items and count to the return stack.
dup \ xn .. x1 N N --
begin
dup
while
rot r> swap >r >r \ xn .. N N -- ; R: .. x1 --
1- \ xn .. N 'N -- ; R: .. x1 --
repeat
drop \ N -- ; R: x1 .. xn --
r> swap >r >r
;

: NR> \ -- xn .. x1 N ; R: x1 .. xn N --
\ Pull N items and count off the return stack.
r> r> swap >r dup
begin
dup
while
r> r> swap >r -rot
1-
repeat
drop
;


: const ( x "<spaces>name" -- )
depth >r ( x ) ( R: n.depth )
: ( x colon-sys ) ( R: n.depth )
depth r> - ( x colon-sys n.size ) ( R: )
n>r ( x ) ( R: i*x n.size )
postpone literal ( ) ( R: i*x n.size )
nr> ( colon-sys n.size ) ( R: )
drop ( colon-sys )
postpone ; ( )
;
=== end code ===

=== begin test ===
123 const foo
ok
foo .
123 ok
=== end test ===
Gerry Jackson
2024-08-11 22:26:00 UTC
Permalink
Post by Ruvim
Do you know a Forth system in which the following definition for "const"
is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
  depth >r          ( x )                   ( R: n.depth )
  :                 ( x colon-sys )         ( R: n.depth )
  depth r> -        ( x colon-sys n.size )  ( R: )
  n>r               ( x )                   ( R: i*x n.size )
  postpone literal  (   )                   ( R: i*x n.size )
  nr>               ( colon-sys n.size )    ( R: )
  drop              ( colon-sys )
  postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.

Therefore I developed my system (for desktop systems only) with a
separate control flow stack. It doesn't stop checking for unbalanced
stack errors. As it is only used when compiling speed isn't important it
can be a linked list implementation discarded at runtime. It allows data
to be passed into or out of colon definitions or other control
structures without considering the control stack unless you are trying
to write portable software.

So in your definition above the use of DEPTH, N>R etc is unnecessary as
DEPTH >R : DEPTH R> -
returns 0 for my system. CONST works.
--
Gerry
Ruvim
2024-08-12 09:00:18 UTC
Permalink
Post by Gerry Jackson
Post by Ruvim
Do you know a Forth system in which the following definition for
"const" is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
   depth >r          ( x )                   ( R: n.depth )
   :                 ( x colon-sys )         ( R: n.depth )
   depth r> -        ( x colon-sys n.size )  ( R: )
   n>r               ( x )                   ( R: i*x n.size )
   postpone literal  (   )                   ( R: i*x n.size )
   nr>               ( colon-sys n.size )    ( R: )
   drop              ( colon-sys )
   postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types <https://forth-standard.org/
standard/usage#subsubsection.3.1.5.1>
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.
This is a more restrictive requirement to the systems, than a
requirement to be independent of the data stack depth.


This requirement can be reasonable. But a problem is that user-defined
control-flow and alike structures will leave their intermediate data on
the data stack anyway (unless they are implemented as parsing words, or
using a user-defined control-flow stack).

Therefore, if the standard will require the control-flow stack be
separate, it should probably provide programs access to this stack (to
save intermediate data in compile time).
Post by Gerry Jackson
Therefore I developed my system (for desktop systems only) with a
separate control flow stack. It doesn't stop checking for unbalanced
stack errors. As it is only used when compiling speed isn't important it
can be a linked list implementation discarded at runtime. It allows data
to be passed into or out of colon definitions or other control
structures without considering the control stack unless you are trying
to write portable software.
So in your definition above the use of DEPTH, N>R etc is unnecessary as
  DEPTH >R : DEPTH R> -
returns 0 for my system. CONST works.
It's possible to implement a library that defines a separate
control-flow stack and redefines all the standard words to use this stack.

It can make sense only if control-flow checking is data stack depth
independent in the Forth system.


--
Ruvim
Gerry Jackson
2024-08-13 19:26:25 UTC
Permalink
Post by Ruvim
Post by Gerry Jackson
Post by Ruvim
Do you know a Forth system in which the following definition for
"const" is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
   depth >r          ( x )                   ( R: n.depth )
   :                 ( x colon-sys )         ( R: n.depth )
   depth r> -        ( x colon-sys n.size )  ( R: )
   n>r               ( x )                   ( R: i*x n.size )
   postpone literal  (   )                   ( R: i*x n.size )
   nr>               ( colon-sys n.size )    ( R: )
   drop              ( colon-sys )
   postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types <https://forth-standard.org/
standard/usage#subsubsection.3.1.5.1>
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the
limited amount of memory available. I also think that the system
should not get in the way of user programs as putting control stack
data on the data stack certainly does.
This is a more restrictive requirement to the systems, than a
requirement to be independent of the data stack depth.
This requirement can be reasonable. But a problem is that user-defined
control-flow and alike structures will leave their intermediate data on
the data stack anyway (unless they are implemented as parsing words, or
using a user-defined control-flow stack).
Therefore, if the standard will require the control-flow stack be
separate, it should probably provide programs access to this stack (to
save intermediate data in compile time).
Yes that would be the case, a separate control stack with existing
associated words CS-PICK CS-ROLL and CS-DROP (because it has been
needed). There is still a need for user defined control structures.
Post by Ruvim
Post by Gerry Jackson
Therefore I developed my system (for desktop systems only) with a
separate control flow stack. It doesn't stop checking for unbalanced
stack errors. As it is only used when compiling speed isn't important
it can be a linked list implementation discarded at runtime. It allows
data to be passed into or out of colon definitions or other control
structures without considering the control stack unless you are trying
to write portable software.
So in your definition above the use of DEPTH, N>R etc is unnecessary as
   DEPTH >R : DEPTH R> -
returns 0 for my system. CONST works.
It's possible to implement a library that defines a separate
control-flow stack and redefines all the standard words to use this stack.
It can make sense only if control-flow checking is data stack depth
independent in the Forth system.
I doubt that a change like a mandated separate control stack would be
accepted as too much existing code would be broken. A possible step in
that direction could be:
- have the default position to be as it is a present i.e. the control
stack to use the data stack or not. Label this as obsolescent
- provision of a word to define the memory region to be used for the
control stack, such a word would have the stack effect ( ad u -- ) where
u is a maximum number of sys type items e.g. orig etc. That would enable
a user to ALLOT or ALLOCATE the memory.

In another discussion I advanced the opinion that transient memory areas
such as PAD and other buffers were also an anachronism due to early
systems being memory limited. ISTM that a similar solution to making
those permanent could be applied to those e.g.
- have the default position as it is at present i.e. transient or not,
marked as obsolescent
- provide words to define the memory region to be used for the currently
transient regions. That could enable <# buffers to be nested, multiple
PADs.
--
Gerry
a***@spenarnc.xs4all.nl
2024-08-12 09:45:39 UTC
Permalink
Post by Gerry Jackson
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.
It alleviates restriction. Marcel Hendrix hated the restrictions of
R> >R and added the socalled "system stack" S> >S that can be used
over definitions. The disadvantage is of course that there are more
regions of memory that you have to keep track of.
I think that added complexity is a more important consideration as
memory usage. The more stacks you have and the more stack items
you keep in registers, the more difficult e.g. task switching becomes.
Post by Gerry Jackson
Therefore I developed my system (for desktop systems only) with a
separate control flow stack. It doesn't stop checking for unbalanced
stack errors. As it is only used when compiling speed isn't important it
can be a linked list implementation discarded at runtime. It allows data
to be passed into or out of colon definitions or other control
structures without considering the control stack unless you are trying
to write portable software.
So in your definition above the use of DEPTH, N>R etc is unnecessary as
DEPTH >R : DEPTH R> -
returns 0 for my system. CONST works.
--
Gerry
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
Gerry Jackson
2024-08-13 19:31:00 UTC
Permalink
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.
It alleviates restriction. Marcel Hendrix hated the restrictions of
R> >R and added the socalled "system stack" S> >S that can be used
over definitions. The disadvantage is of course that there are more
regions of memory that you have to keep track of.
I think that added complexity is a more important consideration as
memory usage. The more stacks you have and the more stack items
you keep in registers, the more difficult e.g. task switching becomes.
As use of a control stack is during compilation, speed is not too
important so why would register(s) be used for it?
--
Gerry
a***@spenarnc.xs4all.nl
2024-08-14 10:58:16 UTC
Permalink
Post by Gerry Jackson
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.
It alleviates restriction. Marcel Hendrix hated the restrictions of
R> >R and added the socalled "system stack" S> >S that can be used
over definitions. The disadvantage is of course that there are more
regions of memory that you have to keep track of.
I think that added complexity is a more important consideration as
memory usage. The more stacks you have and the more stack items
you keep in registers, the more difficult e.g. task switching becomes.
As use of a control stack is during compilation, speed is not too
important so why would register(s) be used for it?
The control stack pointer can be a user variable, so the switching
is automatic. 1) So you are right that it doesn't impose extra
restrictions for task switching.
Probably I was rationalizing that I hate making things more complicated.
Having a separate control flow stack is a complication in itself,
but it makes other things simpler.
I have the example of restricting STATE to [ ] and INTERPRET.
Marcel Hendrix has the example of passing data to a definition.
There are probably more.

1) By swapping the user pointer, all user variables are switched.
Post by Gerry Jackson
--
Gerry
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
Krishna Myneni
2024-08-12 12:09:36 UTC
Permalink
Post by Gerry Jackson
Post by Ruvim
Do you know a Forth system in which the following definition for
"const" is compiled but does not work as expected?
: const ( x "<spaces>name" -- )
   depth >r          ( x )                   ( R: n.depth )
   :                 ( x colon-sys )         ( R: n.depth )
   depth r> -        ( x colon-sys n.size )  ( R: )
   n>r               ( x )                   ( R: i*x n.size )
   postpone literal  (   )                   ( R: i*x n.size )
   nr>               ( colon-sys n.size )    ( R: )
   drop              ( colon-sys )
   postpone ;        (   )
;
t{ 123 const foo -> }t
t{ foo -> 3 }t
Note 3.1.5.1 System-compilation types
<https://forth-standard.org/standard/usage#subsubsection.3.1.5.1>
ISTM that using the data stack to hold the control stack is an
anachronism that was used in early Forth systems because of the limited
amount of memory available. I also think that the system should not get
in the way of user programs as putting control stack data on the data
stack certainly does.
Agreed. Placing control stack items on the data stack shouldn't be
necessary now. I favor standardization of a separate control stack.
Indeed, in kForth it is possible to define const simply as

: const : postpone literal postpone ; ;

No return stack juggling needed because ":" does not introduce anything
onto the data stack. Balancing of control structures are verified.

This is quite useful when passing args to colon defs as well as to
quotations.

My test of Ruvim's code simply validated the portable version for the
current standard.

--
Krishna
mhx
2024-08-12 17:06:39 UTC
Permalink
On Mon, 12 Aug 2024 12:09:36 +0000, Krishna Myneni wrote:
[..]
Post by Krishna Myneni
: const : postpone literal postpone ; ;
No return stack juggling needed because ":" does not introduce anything
onto the data stack. Balancing of control structures are verified.
This is quite useful when passing args to colon defs as well as to
quotations.
Seconded. In iForth the scheme is less rigorous [1], but it is enough
to allow argument passing to code in progress. This has proved
incredibly useful for my iSPICE code generators (the circuit netlist
is completely converted to early binding machine code).

-marcel

[1] If all control info is passed on the S-stack, the stack juggling
becomes too hairy for my taste.
Loading...