The lot of you have contributed to this episode - by discussing the previous episode on local variables.
I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA
More than worth! ;-)
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
-rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
On 31/01/2025 4:42 am, Hans Bezemer wrote:
The lot of you have contributed to this episode - by discussing the previous episode on local variables.
I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA
More than worth! ;-)
Thanks Hans!
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
-rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
Hi,You're welcome.
Thanks for this video and this implementation of locals.
But what about the speed of execution?
I see that the proposed method is slower than the others
Any explainations?
On 31-01-2025 13:45, ahmed wrote:
Hi,You're welcome.
Thanks for this video and this implementation of locals.
But what about the speed of execution?
Well, that will depend a lot. I mean - you're not very honest if you use
the built-in primitives of a Forth compiler. If you want to be honest,
use the reference implementation of Forth 200x. Because primitives
always win from high level code.
I measured a size penalty of 4 times and a performance penalty of 10
times when executing my example DIVIDE word. But then again - 4tH
doesn't support locals natively. So that is to be expected.
That is also the reason why I didn't include these findings. It would be dishonest to compare a high level implementation where others offer a implementation using primitives.
For instance, I'm sure you understand that this benchmark will come out
quite differently if I run it in 4tH.
As I said - you can convenience your way out of everything. And no
matter how fast your Forth, in the end raw assembly will beat
everything, including C.
So next time you want to make a point, yes, your native regular
expression engine *WILL* probably beat even the neatest and most
cleverly designed high level Forth matching routine.
I see that the proposed method is slower than the others
Any explainations?
Yeah, I understand why you like locals, because your stack juggling
skills need some polishing. But I got a video on that: https://youtu.be/gfE8arB3uWk
First the preliminaries:
: ;then postpone exit postpone then ; immediate
: >zero dup xor ;
: spin swap rot ;
These are 4tH-ese, but I'm attached to them. ;-)
( n1 n2 n3 n4 -- n5)
: calc - >r - 100 r> spin */ ;
: tri_mf4
>r rot r> swap >r spin ( c b a R: x )
dup r@ >= if drop drop >zero rdrop ;then
over r@ >= over r@ < and if dup r> swap calc ;then drop
over r@ >= over r@ < and if over r> calc ;then
rdrop drop >zero
;
If you need more speed, inline CALC.
BTW, replace "RDROP" with "R> DROP" if you need to.
Hans Bezemer
On 31/01/2025 4:42 am, Hans Bezemer wrote:
The lot of you have contributed to this episode - by discussing the previous episode on local variables.
I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA
More than worth! ;-)
Thanks Hans!
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
r> -rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
On 31-01-2025 13:45, ahmed wrote:..
Hi,You're welcome.
Thanks for this video and this implementation of locals.
Any explainations?
Yeah, I understand why you like locals, because your stack juggling
skills need some polishing. But I got a video on that: https://youtu.be/gfE8arB3uWk
First the preliminaries:
: ;then postpone exit postpone then ; immediate
: >zero dup xor ;
: spin swap rot ;
These are 4tH-ese, but I'm attached to them. ;-)
( n1 n2 n3 n4 -- n5)
: calc - >r - 100 r> spin */ ;
: tri_mf4
>r rot r> swap >r spin ( c b a R: x )
dup r@ >= if drop drop >zero rdrop ;then
over r@ >= over r@ < and if dup r> swap calc ;then drop
over r@ >= over r@ < and if over r> calc ;then
rdrop drop >zero
;
If you need more speed, inline CALC.
BTW, replace "RDROP" with "R> DROP" if you need to.
Hans Bezemer
I didn't do this comparison for anything but just to test the
possibility to integrate it (use it) in my forth programs which need
speed (fuzzy logic, neural networks).
I'm not arguing anything about forth or 4th, I'm just a user.
On 31-01-2025 16:16, ahmed wrote:
I didn't do this comparison for anything but just to test the
possibility to integrate it (use it) in my forth programs which need
speed (fuzzy logic, neural networks).
I'm not arguing anything about forth or 4th, I'm just a user.
"But what about the speed of execution?"
Well, you wanted an explanation - and you got one: primitives will
always win from fancy, high level implementations. That's why you have
to test your specific implementation if the documentation isn't clear on
how certain features are implemented.
From a user perspective, the story is very simple - pick the one that
fits you. Who am I to argue with what you need? I don't know you and I
don't know the task you want to fulfill.
If I have any beef it's why do you need a 50 line (high level) reference implementation if you can implement the same functionality with one
single cleverly designed line (which is much more Forth like).
And yeah - don't use locals at all. Bad habit. Gee - coming from me,
that's a big surprise.
Hans Bezemer
First the preliminaries:
: ;then postpone exit postpone then ; immediate
: >zero dup xor ;
: spin swap rot ;
These are 4tH-ese, but I'm attached to them. ;-)
( n1 n2 n3 n4 -- n5)
: calc - >r - 100 r> spin */ ;
: tri_mf4
>r rot r> swap >r spin ( c b a R: x )
dup r@ >= if drop drop >zero rdrop ;then
over r@ >= over r@ < and if dup r> swap calc ;then drop
over r@ >= over r@ < and if over r> calc ;then
rdrop drop >zero
;
Hans Bezemer
I studied this version you've prposed: tri_mf4.
I find it amazing, comprehensible (redibility) and very clever (compared
to mine tri_mf1 in the previous post).
Thanks a lot for it.
: tri_mf3 ( x a b c -- mf) { a b c -- } \ locals à la gforth
dup a < if drop 0 exit then
dup a >= over b < and if a - 100 b a - */ exit then
dup b >= over c < and if c swap - 100 c b - */ exit then
drop 0
;
melahi_ahmed@yahoo.fr (ahmed) writes:
: tri_mf3 ( x a b c -- mf) { a b c -- } \ locals à la gforth
dup a < if drop 0 exit then
dup a >= over b < and if a - 100 b a - */ exit then
dup b >= over c < and if c swap - 100 c b - */ exit then
drop 0
;
This seems more in the locals spirit:
: blend { a x b -- n } 100 b x - b a - */ ;
: tri_mf3.1 { x a b c -- mf }
a x <= x b < AND IF b x a blend EXIT THEN
b x <= x c < AND IF b x c blend EXIT THEN
0 ;
...
I'm sure it works - but IMHO it heavily depends on whether those words are primitives or not. E.g. in 4tH this expends to:
: local r> rot rot dup @ over >r >r ! ;: r> r> ! ;
And if I want to be pedantic, I have to include two SWAPs as well for the proper definition of 2>R and 2R>
- not to mention that you sometimes *DON'T* want to initialize your locals.
Another (consequential) disadvantage of this definition is that you have to *DEFINE* your words in reverse - a drawback which it shares with the original ANS LOCALS wordset.
This seems more in the locals spirit:
: blend { a x b -- n } 100 b x - b a - */ ;
: tri_mf3.1 { x a b c -- mf }
a x <= x b < AND IF b x a blend EXIT THEN
b x <= x c < AND IF b x c blend EXIT THEN
0 ;
If I use locals I'm more likely to
use the ANS notation. I notice Forth Inc does too - perhaps why they were so >adverse to conceding to { } .
Paul Rubin <no.email@nospam.invalid> writes:
This seems more in the locals spirit:
: blend { a x b -- n } 100 b x - b a - */ ;
: tri_mf3.1 { x a b c -- mf }
a x <= x b < AND IF b x a blend EXIT THEN
b x <= x c < AND IF b x c blend EXIT THEN
0 ;
Forth has a word WITHIN that should come in handy here:
: tri_mf3.1 { x a b c -- mf }
x a b within IF b x a blend EXIT THEN
x b c within IF b x c blend EXIT THEN
0 ;
Another alternative, assuming a<=b<=c:
: tri_mf3.1 { x a b c -- mf }
case
x a < ?of 0 endof
x b < ?of b x a blend endof
x c < ?of b x c blend endof
0 0
endcase ;
The disadvantage in the latter case is that the above and below cases
are separate, needing another branch and possibly increasing the
number of mispredictions. This can be addressed with:
[undefined] select [if]
: select ( u1 u2 f -- u )
if swap then nip ;
[then]
: tri_mf3.1 { x a b c -- mf }
x a c within if
b x x b < a c select blend
else
0
then ;
In Gforth (development) SELECT is a primitive which hopefully does not branch; in that case you have only one branch here.
- anton
dxf <dxforth@gmail.com> writes:
If I use locals I'm more likely to
use the ANS notation. I notice Forth Inc does too - perhaps why they were so
adverse to conceding to { } .
The reason why Forth, Inc. argued against { } is that they support an existing code base that uses { } for comments; they use { } comments extensively in SwiftForth, and their customers use it, too. They
voted for {: :}, so they obviously don't have a problem with the
ordering of locals in {: :} (which is the same as for { }).
Using WHERE LOCALS| in SwiftForth x64-Linux 4.0.0-RC89 only brings up
the definition of LOCALS|, but no uses. "WHERE {:" brings up the
definition and 5 uses of "{:", all with more than one local; so they obviously do not have a problem with the ordering of locals in {: :}.
Can you elaborate on what you have noticed?
On Sat, 1 Feb 2025 7:26:11 +0000, Anton Ertl wrote:...
[undefined] select [if]
: select ( u1 u2 f -- u )
if swap then nip ;
[then]
: tri_mf3.1 { x a b c -- mf }
x a c within if
b x x b < a c select blend
else
0
then ;
I think it must be:
(the true/false flag must on tos for select as you defined it)
: tri_mf3.1 { x a b c -- mf }
x a c within if
b x a c x b < select blend
else
0
then ;
r $substitute over r@ u<= -78 swap select -rotdup name>compile >r swap name>interpret state @ select
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
r> -rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
dxf <dxforth@gmail.com> writes:
If I use locals I'm more likely to
use the ANS notation. I notice Forth Inc does too - perhaps why they were so >>adverse to conceding to { } .
The reason why Forth, Inc. argued against { } is that they support an >existing code base that uses { } for comments; they use { } comments >extensively in SwiftForth, and their customers use it, too. They
voted for {: :}, so they obviously don't have a problem with the
ordering of locals in {: :} (which is the same as for { }).
- anton
On 1/02/2025 6:50 pm, Anton Ertl wrote:
dxf <dxforth@gmail.com> writes:
If I use locals I'm more likely to
use the ANS notation. I notice Forth Inc does too - perhaps why they were so
adverse to conceding to { } .
The reason why Forth, Inc. argued against { } is that they support an
existing code base that uses { } for comments; they use { } comments
extensively in SwiftForth, and their customers use it, too. They
voted for {: :}, so they obviously don't have a problem with the
ordering of locals in {: :} (which is the same as for { }).
IIRC FI was pressed hard for { } but they wouldn't budge. It was odd
since a single character to delimit a comment was inherently problematic.
I find it hard to believe FI customers wouldn't have jumped at the chance
to get a proper comment scheme and nicer looking locals syntax. As it is
now they're stuck with two lesser things.
Using WHERE LOCALS| in SwiftForth x64-Linux 4.0.0-RC89 only brings up
the definition of LOCALS|, but no uses. "WHERE {:" brings up the
definition and 5 uses of "{:", all with more than one local; so they
obviously do not have a problem with the ordering of locals in {: :}.
Can you elaborate on what you have noticed?
Interesting since...
SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022
85 matches for LOCAL| (a few false positives in that)
0 matches for {: :} (despite being implemented)
Hi,[..]
Thanks for this video and this implementation of locals.
But what about the speed of execution?
The results:
' tri_mf1 is tri_mf ok
timer-reset 1000000 test .elapsed 94.866300ms ok
' tri_mf2 is tri_mf ok
timer-reset 1000000 test .elapsed 96.399100ms ok
' tri_mf3 is tri_mf ok
timer-reset 1000000 test .elapsed 83.403500ms ok
' tri_mf4 is tri_mf ok
timer-reset 1000000 test .elapsed 211.670300ms ok
I see that the proposed method is slower than the others
Any explainations?
Interesting since...
SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022
85 matches for LOCAL| (a few false positives in that)
0 matches for {: :} (despite being implemented)
dxf <dxforth@gmail.com> writes:
Interesting since...
SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022
85 matches for LOCAL| (a few false positives in that)
0 matches for {: :} (despite being implemented)
Apparently your search for {: is broken. Here's what I get:
...
Apparently the use of LOCALS| is connected mostly with win32 files,
which do not come with 4.0.0-RC89 in the version I use. And most of
the remaining uses of LOCALS| are in unsupported libraries, in
particular the Forth Scientific Library. The tool I used for this is ripgrep, if anybody is wondering.
...
{ } is used for comment in Pascal.
On 2025-01-31 11:33, dxf wrote:
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
r> -rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
This approach does not work well with catch/throw. Because `throw` must restore the values of all "local" variables that are used in the definitions whose execution is being terminated. And this is difficult to implement.
...
On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
{ } is used for comment in Pascal.
That's interesting. When did that come in, and why, given the issues?
dxf <dxforth@gmail.com> writes:
On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
{ } is used for comment in Pascal.
That's interesting. When did that come in, and why, given the issues?
Good question. My memory is only of (* *), but indeed Section 6.1.8
of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
and { can be used interchangeably, as well as *) and }.
dxf <dxforth@gmail.com> writes:
On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
{ } is used for comment in Pascal.
That's interesting. When did that come in, and why, given the issues?
Good question. My memory is only of (* *), but indeed Section 6.1.8
of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
and { can be used interchangeably, as well as *) and }.
- anton
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
r> -rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
This approach does not work well with catch/throw. Because `throw` must >restore the values of all "local" variables that are used in the
definitions whose execution is being terminated. And this is difficult
to implement.
See also 13.3.3.1, item c, ><https://forth-standard.org/standard/locals#subsubsection.13.3.3.1>
| ABORT shall release all local storage resources,
| and CATCH / THROW (if implemented) shall release
| such resources for all definitions whose execution
| is being terminated.
--
Ruvim
The first publication of Pascal was IIRC
1975
Pascal , user manual and report.
Jensen/Wirth
ISBN 0-387-90144-2
Uses { } in all examples, and it is referenced in chapter 1, briefly.
albert@spenarnc.xs4all.nl writes:
The first publication of Pascal was IIRC
1975
Pascal , user manual and report.
Jensen/Wirth
ISBN 0-387-90144-2
Uses { } in all examples, and it is referenced in chapter 1, briefly.
I also have a book on Pascal: "Pascal Handbuch" by E. Floegel. In
Figure 3.31 on page 15 it shows (* and *), but not { and } as
"Verwendete Zeichen in Pascal" (used characters in Pascal, although
the intention is probably to show the symbolic lexemes).
I would be interested to see a remotely plausible example of this.
Mixing recursion and exception is ill advised by iq<160.
albert@spenarnc.xs4all.nl writes:
I would be interested to see a remotely plausible example of this.
Mixing recursion and exception is ill advised by iq<160.
The recursive function calls something that throws an exception, and it should be ok to think about those things separately.
In article <vnkvvq$2a5o$1@dont-email.me>, Ruvim <ruvim.pinka@gmail.com> wrote:
On 2025-01-31 11:33, dxf wrote:
Not sure if previously mentioned but here's another version of LOCAL
: ;: >r ;
: LOCAL ( x adr -- )
r> -rot dup @ over 2>r ! ;: 2r> ! ;
variable A variable B 8 a ! 7 b !
: divide ( a b -- ) b local a local
a @ b @ / . cr ;
15 3 divide a ? b ?
This approach does not work well with catch/throw. Because `throw` must
restore the values of all "local" variables that are used in the
definitions whose execution is being terminated. And this is difficult
to implement.
See also 13.3.3.1, item c,
<https://forth-standard.org/standard/locals#subsubsection.13.3.3.1>
| ABORT shall release all local storage resources,
| and CATCH / THROW (if implemented) shall release
| such resources for all definitions whose execution
| is being terminated.
Nice catch!
However, this is highly artificial. You have to have a recursive routine in this
vein:
RECURSIVE
: fun .. fun ... fun . 'fun CATCH .. fun ... ;
otherwise the global VARIABLE's can be ignored.
I would be interested to see a remotely plausible example of this.
Mixing recursion and exception is ill advised by iq<160.
On 2025-02-02 15:13, albert@spenarnc.xs4all.nl wrote:
Recursion is not necessary. It is enough to use the same-name "local" >variables in different functions, some of which throw exceptions, and
other catch exceptions.
An artificial example:
: local ( x2 addr1 -- ; R: nest-sys1 -- x1 addr1 nest-sys.xt nest-sys1 )
\ This definition assumes that nest-sys size is 1 cell,
\ and xt is a subtype of nest-sys
r> ( x2 addr nest-sys1 )
over dup @ >r >r [: 2r> ! ;] >r
( x2 addr1 nest-sys1 ) >r !
;
: idiv ( n1 n2\0 -- n3 | n1 0 -- never )
dup if / exit then -10 throw
;
variable a
variable b
: foo ( n1 n2 -- )
b local a local
a @ b @ idiv
." idiv result is " . cr
;
: bar ( u1 -- u1 )
a local
100 a @ ['] foo catch if 2drop then
a @
;
0 bar .
\ this must print 0, but will print 10
----
Ruvim
I maintain that if you are not in a recursive call for
a function with locals, and you try to catch the same function
call, everything is fine.
albert@spenarnc.xs4all.nl writes:Yeah right.
I maintain that if you are not in a recursive call for
a function with locals, and you try to catch the same function
call, everything is fine.
The thing about exceptions is that they occur unexpectedly.
your recursive function prints something, and that works the first few
times, but then the printer runs out of paper and there is an i/o
exception. It's not the recursive function's job to handle this. The >exception throws to some outer level handler that asks the user to fix
the problem.
Adding (LOCAL) to a Forth interpreter should normally not be too
difficulot, if you control the interpreter implementation. It's the
right way to do stuff like this. Why mess around with all that awful
stack juggling for a half-working and woefully slow solution?
dxf <dxforth@gmail.com> writes:
On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
{ } is used for comment in Pascal.
That's interesting. When did that come in, and why, given the issues?
Good question. My memory is only of (* *), but indeed Section 6.1.8
of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
and { can be used interchangeably, as well as *) and }.
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
dxf <dxforth@gmail.com> writes:
On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
{ } is used for comment in Pascal.
That's interesting. When did that come in, and why, given the issues?
Good question. My memory is only of (* *), but indeed Section 6.1.8
of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
and { can be used interchangeably, as well as *) and }.
'{' and '}' are original Pascal comments. I do not think they have
any issue beyond normal ones, that is inability to put '}' as
part of a comment. Since comments were intended to be text and
'}' is not used as normal part of text presumably inability to
put '}' inside a comment was deemed as non-issue.
Pascal was bases on ASCII, but IBM mainframes used EBCDIC which
missed several useful ASCII characters, notably '{', '}',
'[', '[', so Pascal implementations on IBM mainframes used
alternate sequences. The alternative seqences were standarized
together with originals.
More generally, Wirth had rather rigid view how "good" program
should look like and this view was enforced by Pascal compilers.
Practical Pascals and later Extended Pascal were much more
flexible.
... if they are absolutely necessary I use my enhanced `[ instead
of any style of locals
: root [ variable a variable b variable c ]
c ! b ! a !
\ now insert the famous quadratic root formula
[ hide a hide b hide c ] \ Prevent "not unique messages"
;
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
... if they are absolutely necessary I use my enhanced `[ instead
of any style of locals
: root [ variable a variable b variable c ]
c ! b ! a !
\ now insert the famous quadratic root formula
[ hide a hide b hide c ] \ Prevent "not unique messages"
;
Hello Albert,
why is an enhanced [ necessary for this?
Couldn't you simply write:
variable a variable b variable c
: root ( a b c -- root)
c ! b ! a !
\ now insert the famous quadratic root formula
;
hide a hide b hide c \ Prevent "not unique messages"
Henry
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
Given that a Forth system supports quotations and xt-locals,
nested definitions are easy to implement. BTW xt-locals exist
f.ex. in gforth. They hold xt's and when called execute the xt
instead of pushing it to the stack as normal locals would do.
With my enhanced [ ] pair, you can introduce whatever local
widgets, in particular objects, you choose.
The goal of language design is not to overload with features
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
Given that a Forth system supports quotations and xt-locals,
nested definitions are easy to implement.
BTW xt-locals exist
f.ex. in gforth. They hold xt's and when called execute the xt
instead of pushing it to the stack as normal locals would do.
minforth@gmx.net (minforth) writes:
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
Given that a Forth system supports quotations and xt-locals,
nested definitions are easy to implement.
You mean:
: foo [: ." xyz" ;] {: xt: bar :} bar ;
Sure, you then get a local that behaves similar to a nested
definition, but I don't think anyone would want to do that.
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:
minforth@gmx.net (minforth) writes:
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
Given that a Forth system supports quotations and xt-locals,
nested definitions are easy to implement.
You mean:
: foo [: ." xyz" ;] {: xt: bar :} bar ;
Sure, you then get a local that behaves similar to a nested
definition, but I don't think anyone would want to do that.
Yes, that's the mechanism. Actually I use it with some syntactic
sugar for better readability:
: foo
<: bar ." xyz" ;>
bar
;
I find this quite handy, since upvalues (locals within foo's
context) are accessible from within bar.
: foo
<: bar ." xyz" ;>
bar
;
I find this quite handy, since upvalues (locals within foo's
context) are accessible from within bar.
On 7/02/2025 12:59 am, minforth wrote:
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:AFAIR 200x nested definitions were justified on the grounds named
definitions were neither needed nor wanted
and access to external
locals not necessary.
dxf <dxforth@gmail.com> writes:
On 7/02/2025 12:59 am, minforth wrote:
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:AFAIR 200x nested definitions were justified on the grounds named
definitions were neither needed nor wanted
Really? There's a proposal to eliminate named definitions? That's
news to me.
There are cases where you need to pass an xt to some word, and where
the xt does not merit a name, e.g.,
...
and access to external
locals not necessary.
It's more that anything proper is pretty hard to implement and there
was not enough demand for that nor existing practice that anybody
wanted to propose for standardization.
However, the topic came up repeatedly in discussions, so in 2018 I sat
down to investigate the issue. After a while I had a paper design,
but had my doubts that it is worth implementing it. I let Bernd
Paysan read the paper, and he came up with further simplifications and implemented the result; the changes were so deep that I had to mostly
rewrite the paper, resulting in our EuroForth 2018 paper
[ertl&paysan18]. And Bernd embraced using the resulting closures.
I still had my doubts about whether one really needs that, as I had
not found a short example that showed a clear advantage over the alternatives. I asked Niklaus Wirth, who had kept access to outer
locals in his languages for many decades, but his answer was that he
finally removed that feature from Oberon 07 in 2013, and he did not
provide such an example, either.
Finally, such a usage was found by Bernd Paysan: He had implemented a
variant of the actor model
<https://gforth.org/manual/Message-queues.html> (inspired by Heinz Schnitter's Open Network Forth):
One task sends a message consisting of an xt to another task, and the
other task then executes it. But sending just an xt without any data
is not very useful, so one could also send integers, strings, etc.
The sender would send the data and then the xt, and the receiving task
would push the data on the stack, and then execute the xt. However,
several tasks can send messages to one task at the same time, so there
was some additional twist to avoid mixing the parts of a message of
one task with the parts of a message of another task. With closures
that all became unnecessary: The data is part of the passed xt.
Another development was pure-stack closures.
But none of this existed when quotations were accepted for
standardization.
...
On Thu, 6 Feb 2025 11:11:28 +0000, albert@spenarnc.xs4all.nl wrote:
With my enhanced [ ] pair, you can introduce whatever local
widgets, in particular objects, you choose.
The goal of language design is not to overload with features
But haven't you overloaded the old [ ] with new features now? ;-)
There is indeed a restriction in standard §3.4:
"A program shall not attempt to nest compilation of definitions.
During the compilation of the current definition, a program
shall not execute any defining word, :NONAME, or any definition
that allocates dictionary data space."
However because local names are not compiled into dictionary data
space, but use their own transient dictionary entries, which
disappear after compilation, this restriction as of $3.4 does not
apply to embedded functions emulated by xt-locals, aka
defer-flavoured locals.
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:You mean
minforth@gmx.net (minforth) writes:
On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
Remark that is doesn't introduce any unfamiliar syntax,
only does away with "Forth shall not nested definitions"
(Says who?)
Given that a Forth system supports quotations and xt-locals,
nested definitions are easy to implement.
You mean:
: foo [: ." xyz" ;] {: xt: bar :} bar ;
Sure, you then get a local that behaves similar to a nested
definition, but I don't think anyone would want to do that.
Yes, that's the mechanism. Actually I use it with some syntactic
sugar for better readability:
: foo
<: bar ." xyz" ;>
bar
;
I find this quite handy, since upvalues (locals within foo's
context) are accessible from within bar.
Yes, that's the mechanism. Actually I use it with some syntactic
sugar for better readability:
: foo
<: bar ." xyz" ;>
bar
;
You mean
: foo
[ : bar ." xyz" ; ]
bar
;
However because local names are not compiled into dictionary data
space, but use their own transient dictionary entries, which
minforth@gmx.net (minforth) writes:
: foo
<: bar ." xyz" ;>
bar
;
I find this quite handy, since upvalues (locals within foo's
context) are accessible from within bar.
Do you implement proper static scoping? I.e., does your system pass
the man-or-boy test. What about returning xts that reference outer
locals, e.g.:
: n+ ( n -- xt ) {: n :} [: n + ;] ;
5 n+ constant 5+
3 5+ execute .
7 5+ execute .
Where does this self-limiting backwardness come from?
Virtually all modern embedded devices communicate with
their outside world, and multitasking comes naturally.
On the software side, closures can be a very helpful
tool for communication and task management.
So virtually all modern programming languages support
closures (albeit with subtle nuances). I think a modern
Forth should not be closed to modern programming concepts.
DOS is finally history.
However, does this work in gforth?
: n+ ( n -- xt ) {: n :} [: n + ;] ;
5 n+ constant 5+
10 n+ constant 10+ ( 2nd instance )
2 5+ . ( 7 )
2 10+ . ( 12 )
3 5+ . ( 8 )
On 7/02/2025 4:20 am, Anton Ertl wrote:
dxf <dxforth@gmail.com> writes:
On 7/02/2025 12:59 am, minforth wrote:
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:AFAIR 200x nested definitions were justified on the grounds named
definitions were neither needed nor wanted
Really? There's a proposal to eliminate named definitions? That's
news to me.
I didn't but clearly those that argued for quotations did.
There's a case for having NONAME: which has no name and must pass an xt.
But that's not the same as saying there's a need for definitions without >names.
This only strengthened my view forth quotations had nothing to offer but >namelessness.
If want to hide names of definitions I no longer need to
reference I have BEHEAD for that.
Interesting but what are you saying - that quotations as we have them
are little more than a gimmick?
dxf <dxforth@gmail.com> writes:
On 7/02/2025 4:20 am, Anton Ertl wrote:
dxf <dxforth@gmail.com> writes:
On 7/02/2025 12:59 am, minforth wrote:
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:AFAIR 200x nested definitions were justified on the grounds named
definitions were neither needed nor wanted
Really? There's a proposal to eliminate named definitions? That's
news to me.
I didn't but clearly those that argued for quotations did.
They did what? Make a proposal for eliminating named definitions?
Where can I find that proposal? I was one of the proposers of
quotations, so I certainly argued for them, and I am completely
unaware of a proposal like you claim, neither from me, nor Alex
McDonald (the first proposer of quotations), nor of anybody else
arguing for quotations. Please present evidence of such a proposal.
There's a case for having NONAME: which has no name and must pass an xt.
Let's look at an example from the proposal:
: hex. ( u -- )
base @ >r
[: hex u. ;] catch
r> base ! throw ;
There is no good way for replacing the quotation here with NONAME:, so NONAME: is a red herring.
This only strengthened my view forth quotations had nothing to offer but
namelessness.
They also offer nesting.
Thanks, that makes sense. Each call to the outer function
creates a data record for (the contexts of) each of its inner
closure(s). The context records need to be managed somehow.
quotations ... strike me as being wrong in every way, not least
because they are intended to feature prominently, stuffed in one's
face. I don't understand the appeal at all.
minforth@gmx.net (minforth) writes:
Thanks, that makes sense. Each call to the outer function
creates a data record for (the contexts of) each of its inner
closure(s). The context records need to be managed somehow.
Most languages with closures also have garbage collection, or anyway scope-controlled deallocation like in C++. It may not be obvious, but closures are sort of the same thing as OOP, just viewed from a different angle. Storage for the internal data of OOP instances has to be managed
in about the same way.
dxf <dxforth@gmail.com> writes:
quotations ... strike me as being wrong in every way, not least
because they are intended to feature prominently, stuffed in one's
face. I don't understand the appeal at all.
I never got the impression they were supposed to be so prominent, though
I guess one could program in a style that uses them heavily.
My first
Forth program used a lot of XT's but in retrospect, it was rather unidiomatic.
The following sort of follows an idiom for Python GUI programs. You
have a function MAKE-BUTTON that puts a button on the screen. The
button has a label, and it calls a function when you press it. This
is using the notation from Anton's post but I haven't tested it.
: make-button ( a u xt -- ) ... ;
\ a u is the label, xt is the action
Now you want to draw buttons for a numeric keypad:
: make-action ( n -- xt ) [n:d ." You pressed " . ] ;
: make-label ( n -- a u ) \ make a string like "5" in the dictionary
here { a } 1 chars allot '0' + a c! a 1 ;
: keypad ( -- ) 10 0 do
i make-label i make-action make-button
loop ;
Now there will be buttons labelled "0", "1", ... "9", and and when you
press one, it will print "you pressed 5" or whatever for that button.
I think the idiomatic old-school Forth alternative to this would be an OOP-like approach, but the above is probably more concise, and to some
of us more intuitive.
IMO it does nothing for readability to see a definition interrupted by another. My reaction is one of WTF.
: make-action ( n -- xt ) [n:d ." You pressed " . ] ;I don't understand make-action at all. What is it meant to be doing?
Call me boring but I don't like inventing new syntax only to have to
the antithesis of Forth - the opposite of being simple.
So are quotations worth it for Forth? I don't know. I see some uses
for them but I'd tend to say that style is more common in GC'd
languages.
What language do you know where
nested definitions are nameless?
It may not be obvious, but
closures are sort of the same thing as OOP, just viewed from a different >angle.
The :}D means that the closure data is stored in the dictionary; there
is also :}L (for locals, deallocated when the surrounding definition
is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap, deallocated right after the first (and only) execution).
"There's a need for definitions without names" is something completely >different than "named definitions were neither needed nor wanted".
- anton
dxf <dxforth@gmail.com> writes:
What language do you know where
nested definitions are nameless?
Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
longer list can be found at ><https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.
- anton
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
The :}D means that the closure data is stored in the dictionary; there
is also :}L (for locals, deallocated when the surrounding definition
is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap,
deallocated right after the first (and only) execution).
This is pretty cool, but it looks like quotations within the closure
aren't allowed to access the closure's locals, using them as OOP-like
state. In the current Gforth git snapshot:
: x [{: n :}d [: n 1+ dup to n ;] ;]h 0 execute ;
gives:
*the terminal*:26:30: error: Unsupported operation
: x [{: n :}d [: n 1+ dup to >>>n<<< ;] ;]h 0 execute ;
This is an attempt to make a counting function, like in Scheme:
(define (x)
((lambda (n)
(lambda ()
(set! n (+ 1 n))
n)) 0))
(define a (x))
(a) ; 1
(a) ; 2, etc.
FWIW a single quotation-based counter in another Forth:
MinForth 3.6 (32 bit)
# defer ctr ok
# : init { n } [: n 1+ dup to n ;] ; ok
# 4 init is ctr ok
# ctr . 5 ok
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
The :}D means that the closure data is stored in the dictionary; there
is also :}L (for locals, deallocated when the surrounding definition
is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap,
deallocated right after the first (and only) execution).
This is pretty cool, but it looks like quotations within the closure
aren't allowed to access the closure's locals
This is an attempt to make a counting function, like in Scheme:
(define (x)
((lambda (n)
(lambda ()
(set! n (+ 1 n))
n)) 0))
(define a (x))
(a) ; 1
(a) ; 2, etc.
It would be interesting if your conservative gc could be made reliable
and included with gforth, and then another suffix could be added to put >closure locals in the gc'd heap.
Also in a threaded
program I guess it would have to stop any threads that shared a GC'd
heap during collection of that heap.
minforth@gmx.net (minforth) writes:
FWIW a single quotation-based counter in another Forth:
MinForth 3.6 (32 bit)
# defer ctr ok
# : init { n } [: n 1+ dup to n ;] ; ok
# 4 init is ctr ok
# ctr . 5 ok
Questions:
1) where does the storage cell for n live, after init has returned?
2) what if you make more than one counter?
3) why did you use defer instead of something like CONSTANT?
thanks
dxf <dxforth@gmail.com> writes:
What language do you know where
nested definitions are nameless?
Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
longer list can be found at <https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.
Paul Rubin <no.email@nospam.invalid> writes:..
This is an attempt to make a counting function, like in Scheme:
(define (x)
((lambda (n)
(lambda ()
(set! n (+ 1 n))
n)) 0))
(define a (x))
(a) ; 1
(a) ; 2, etc.
: x ( -- xt )
here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;
x alias a
x alias b
a . \ 1
a . \ 2
b . \ 1
a . \ 3
- anton
On Sun, 9 Feb 2025 23:08:22 +0000, Anton Ertl wrote:...
Paul Rubin <no.email@nospam.invalid> writes:..
This is an attempt to make a counting function, like in Scheme:
(define (x)
((lambda (n)
(lambda ()
(set! n (+ 1 n))
n)) 0))
(define a (x))
...: x ( -- xt )
here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;
x alias a
: ctr: create 0 , does> dup @ 1+ dup rot ! ; ok...
ctr: a
So, what is the difference between the two definitions?
If you want heap allocation (i.e., to be able to reclaim the memory
when you no longer need the counter), you can do it with closures, but
not with DOES>:
melahi_ahmed@yahoo.fr (ahmed) writes:
On Sun, 9 Feb 2025 23:08:22 +0000, Anton Ertl wrote:...
Paul Rubin <no.email@nospam.invalid> writes:..
This is an attempt to make a counting function, like in Scheme:
(define (x)
((lambda (n)
(lambda ()
(set! n (+ 1 n))
n)) 0))
(define a (x))
...: x ( -- xt )
here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;
x alias a
: ctr: create 0 , does> dup @ 1+ dup rot ! ; ok...
ctr: a
So, what is the difference between the two definitions?
One produces an xt, the other a named word; the latter is more
convenient for the shown usage).
But yes, for dictionary allocation Forth has had a way to associate
data with a single action since very early on.
ALLOC moves a word to the heap freeing the a freshly generated objectthat runs from ( addr --) to HERE. This doesn't switch DP, and assumes relocatable code.
ALLOC \ move to heapWORDS \ to show that test has vanished
But, as mentioned below, the textbook examples of changing data in
closures or DOES> words are rarely found in practice.
- anton--
If you want heap allocation (i.e., to be able to reclaim the memory
when you no longer need the counter), you can do it with closures, but
not with DOES>:
You can just FORGET the word.
-marcel--
On 10/02/2025 2:45 am, Anton Ertl wrote:
dxf <dxforth@gmail.com> writes:
What language do you know where
nested definitions are nameless?
Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
longer list can be found at
<https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.
"The use of anonymous functions is a matter of style. Using them is never
the only way to solve a problem; each anonymous function could instead be defined as a named function and called by name."
So it's a style - a fashion statement.
You can just FORGET the word.
: x ( -- xt )
here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;
: x ( -- xt )
0 <{: w^ n :}d n ;> drop [{: n :}d n @ 1+ dup n ! ;] ;
another suffix could be added to put closure locals in the gc'd heap.Yes. There is :}xt for passing an xt that performs the allocation.
See <https://gforth.org/manual/Closures.html> for all of these topics.
Also in a threaded program I guess it would have to stop any threads
that shared a GC'd heap during collection of that heap.
That's a tough one. My current thinking is along the lines of a
per-thread allocator and garbage-collector, with no heap-allocated
data passed between threads. Then thread-unaware GCs are good enough.
Unfortunately, everything is very non-standard, as there is
no multitasking wordset (for historical reasons?).
A pity really, as co-operative multitasking existed very
early on in Forth.
Then it would be easier to have better discussions about coroutines
(the original topic of this thread) or ownership of closure objects
and different variants of GC.
minforth@gmx.net (minforth) writes:
Unfortunately, everything is very non-standard, as there is
no multitasking wordset (for historical reasons?).
A pity really, as co-operative multitasking existed very
early on in Forth.
I had thought there wasn't enough agreement about the wordset to
standardize it, and the same thing happened for cross development. But
at least for multitasking, there is reasonable shared understanding
about how it should work, at least in the cooperative case.
Then it would be easier to have better discussions about coroutines
(the original topic of this thread) or ownership of closure objects
and different variants of GC.
I think these fancy closures are mostly of interest to language geeks
and not so much in the old-fashioned Forth spirit. Coroutines don't
seem that important if you have multitasking. Anton's GC is great and I >think cooperative multitasking wouldn't affect it much, if you don't
mind the collection pauses. It would simply block during collection.
minforth@gmx.net (minforth) writes:
Unfortunately, everything is very non-standard, as there is
no multitasking wordset (for historical reasons?).
A pity really, as co-operative multitasking existed very
early on in Forth.
I had thought there wasn't enough agreement about the wordset to
standardize it
On Tue, 11 Feb 2025 22:17:31 +0000, Paul Rubin wrote:
minforth@gmx.net (minforth) writes:
Unfortunately, everything is very non-standard, as there is
no multitasking wordset (for historical reasons?).
A pity really, as co-operative multitasking existed very
early on in Forth.
I had thought there wasn't enough agreement about the wordset to
standardize it
Likely dead or too little support: >https://forth-standard.org/proposals/multi-tasking-proposal
Here's the simple locals paradigm using VALUEs. OTOH it's likely
to be less portable than the VARIABLE-based one.
: ;: >r ;
: (local) ( x xt -- ) \ assume CREATE-based VALUEs
r> -rot dup execute over 2>r >body ! ;: 2r> >body ! ;
: LOCAL ( x "name" -- )
' postpone literal postpone (local) ; immediate
\ behead (local) (local)
\ Example
8 value A 7 value B
: divide ( a b -- ) local b local a
a b / . cr ;
15 3 divide a . b .
...
But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:
: (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;
Back ported to Gforth - it works!
...
On 20/03/2025 11:07 pm, Hans Bezemer wrote:
...
But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:
: (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;
Back ported to Gforth - it works!
...
Slightly smaller (for me) and not less portable. Thanks!
On 21/03/2025 11:38 am, dxf wrote:
On 20/03/2025 11:07 pm, Hans Bezemer wrote:
...
But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:
: (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;
Back ported to Gforth - it works!
...
Slightly smaller (for me) and not less portable. Thanks!
The run-time code can be reduced further by relocating >BODY ...
: (local) ( x adr -- ) r> -rot dup @ over 2>r ! ;: 2r> ! ;
: LOCAL ( x "name" -- )
' >body postpone literal postpone (local) ; immediate
...
Nice test - I bet it wouldn't be too hard to implement at least part of the Forth-200x implementation ;-)
Sometin' like define {:
1. Parse a word;
2. If not :} then create a (local);
3. Repeat.
Ok, this is horrible code, it needs the VALUES in reverse, but it works:
: :} ;
: {: begin ' dup ['] :} <> while >body postpone literal postpone (local) repeat drop ; immediate
: test {: b a :} a b / ;
An artificial example:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
On 23/03/2025 2:51 am, sjack wrote:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
Does anyone have a reference/details for this anywhere as I can't seem to find anything?
A possibly useful hit but the doc is locked away:
https://doi.org/10.1145/165628.165637
On 23/03/2025 2:51 am, sjack wrote:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
Does anyone have a reference/details for this anywhere as I can't seem to find anything?
A possibly useful hit but the doc is locked away:
https://doi.org/10.1145/165628.165637
Does anyone have a reference/details for this anywhere as I can't seem to find anything?
But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT:
and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th
?????????? ???????????? ???????? ? ??????? (???????????)
?.?.?????????
?????-????????????? ???????? ??????????? ? ????????????? ???
199178, ?????-?????????, 14-? ????? ?.?., ?.39
?-mail: mlg@iias.spb.su
On 23-03-2025 04:03, dxf wrote:
On 23/03/2025 2:51 am, sjack wrote:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
Does anyone have a reference/details for this anywhere as I can't seem to
find anything?
A possibly useful hit but the doc is locked away:
https://doi.org/10.1145/165628.165637
Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt
But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th
It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th
: CUT: \ mark the beginning of the fragment to cut
R> RP@ >L \ copy r-stack top addr. to L-stack
BACK LDROP TRACKING \ delete this mark when backtracking
>R ;
: -CUT R> L> RP! >R ; \ delete return points upto the marked addr.
: -NOCUT \ remove the mark, but not the return points
R>
L> RP@ - >R \ keep the mark as a relative address
BACK R> RP@ + >L TRACKING \ restore it when backtracking
>R ;
On 23/03/2025 10:25 pm, Hans Bezemer wrote:
On 23-03-2025 04:03, dxf wrote:
On 23/03/2025 2:51 am, sjack wrote:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
Does anyone have a reference/details for this anywhere as I can't seem to >>> find anything?
A possibly useful hit but the doc is locked away:
https://doi.org/10.1145/165628.165637
Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt
But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th
It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th
: CUT: \ mark the beginning of the fragment to cut
R> RP@ >L \ copy r-stack top addr. to L-stack
BACK LDROP TRACKING \ delete this mark when backtracking
>R ;
: -CUT R> L> RP! >R ; \ delete return points upto the marked addr.
: -NOCUT \ remove the mark, but not the return points
R>
L> RP@ - >R \ keep the mark as a relative address
BACK R> RP@ + >L TRACKING \ restore it when backtracking
>R ;
Thank you (and sjack) for chasing down this one. More detail appears to be available in the SP-Forth sources directory: \devel\~profit\lib\bac4th.f
A CP1251 to Unicode converter is here:
https://convertcyrillic.com/#/convert
On 23/03/2025 10:25 pm, Hans Bezemer wrote:
On 23-03-2025 04:03, dxf wrote:
On 23/03/2025 2:51 am, sjack wrote:
Ruvim <ruvim.pinka@gmail.com> wrote:
An artificial example:
While wondering down roads less taken, I took a path where
bacForth CUT: and -CUT were used in lieu of CATCH THROW .
Does anyone have a reference/details for this anywhere as I can't seem to >>> find anything?
A possibly useful hit but the doc is locked away:
https://doi.org/10.1145/165628.165637
Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt
But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th
It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th
: CUT: \ mark the beginning of the fragment to cut
R> RP@ >L \ copy r-stack top addr. to L-stack
BACK LDROP TRACKING \ delete this mark when backtracking
>R ;
: -CUT R> L> RP! >R ; \ delete return points upto the marked addr.
: -NOCUT \ remove the mark, but not the return points
R>
L> RP@ - >R \ keep the mark as a relative address
BACK R> RP@ + >L TRACKING \ restore it when backtracking
>R ;
Thank you (and sjack) for chasing down this one. More detail appears to be available in the SP-Forth sources directory: \devel\~profit\lib\bac4th.f
A CP1251 to Unicode converter is here:
https://convertcyrillic.com/#/convert
...
M. Gassanenko's original doc with code is in directory: \devel\~mlg
Don't know whether I should be surprised or not but after passing through Google Translate the result is amazingly good English.
On 24/03/2025 1:52 pm, dxf wrote:
...
M. Gassanenko's original doc with code is in directory: \devel\~mlg
Don't know whether I should be surprised or not but after passing through
Google Translate the result is amazingly good English.
For anyone interested I've uploaded the translation to my google drive as:
Backtracking.htm
https://drive.google.com/drive/folders/1kh2WcPUc3hQpLcz7TQ-YQiowrozvxfGw
Unlike "gassanenko96b.txt" (earlier version in English?) the translation
has the source code.
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 1,030 |
Nodes: | 10 (0 / 10) |
Uptime: | 04:47:59 |
Calls: | 13,343 |
Calls today: | 6 |
Files: | 186,574 |
D/L today: |
5,696 files (1,682M bytes) |
Messages: | 3,357,269 |