• EuroForth 2025 preliminary proceedings

    From dxf@dxforth@gmail.com to comp.lang.forth on Thu Jan 15 17:41:04 2026
    From Newsgroup: comp.lang.forth

    As I had trouble finding it, perhaps others too. Here's the link:

    http://www.euroforth.org/ef25/papers/

    There is no link from the main page.

    Someone had referenced Nick Nelson's 'Forth 2025' paper and I was curious
    to read it.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Jan 15 12:04:13 2026
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    As I had trouble finding it, perhaps others too. Here's the link:

    http://www.euroforth.org/ef25/papers/

    There is no link from the main page.

    Thank you. As it happens, yesterday I created the post-conference
    proceedings that includes a late paper and the slides that were
    provided by their authors (not that many; apparently many authors are
    content with the prospect of their presentation being preserved on
    video). I have now updated various links for the post-conference
    state (link from www.euroforth.org to proceedings, and from the
    proceedings to the euro.theforth.net page).

    Unfortunately, the videos are not yet available. Gerald Wodni has not
    yet had the time to process them. He mentioned something like "after
    January" or somesuch.

    I think that submitting slides has not just the advantage that they
    are published earlier in this case (or at all in the 2023 case, where
    the audio was so problematic that most videos were not published), but
    also that one can read them faster than watch a video; the videos have
    the audio track and interactive demos in addition to the text and
    graphics of the slides, though.

    - 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: https://forth-standard.org/
    EuroForth 2025 CFP: http://www.euroforth.org/ef25/cfp.html
    EuroForth 2025 registration: https://euro.theforth.net/
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Jan 16 15:25:22 2026
    From Newsgroup: comp.lang.forth

    On 15-01-2026 13:04, Anton Ertl wrote:

    A few observations concerning the IMHO most interesting paper,
    "Code-Copying Compilation in Production":

    1. Code copying indeed makes a big difference, overall I estimate about
    twice as fast;
    2. The performance of VFX Forth continues to impress me, keeping up
    nicely, even with C compiled code;
    3. Commercial compilers (partly) using conventional compilers (see TF,
    fig. 4.7) - that was new to me;
    4. GCC -O1 outperforming GCC -O3 on some benchmarks. That's new to me
    too. I might experiment with that one;
    5. I added GCC extension support to 4tH in version 3.62.0. At the time,
    it improved performance by about 25%. By accident I found out that was
    no longer true. switch() based was faster. I didn't know there had been changes in that regard to GCC.

    Hans Bezemer

    dxf <dxforth@gmail.com> writes:
    As I had trouble finding it, perhaps others too. Here's the link:

    http://www.euroforth.org/ef25/papers/

    There is no link from the main page.

    Thank you. As it happens, yesterday I created the post-conference proceedings that includes a late paper and the slides that were
    provided by their authors (not that many; apparently many authors are
    content with the prospect of their presentation being preserved on
    video). I have now updated various links for the post-conference
    state (link from www.euroforth.org to proceedings, and from the
    proceedings to the euro.theforth.net page).

    Unfortunately, the videos are not yet available. Gerald Wodni has not
    yet had the time to process them. He mentioned something like "after January" or somesuch.

    I think that submitting slides has not just the advantage that they
    are published earlier in this case (or at all in the 2023 case, where
    the audio was so problematic that most videos were not published), but
    also that one can read them faster than watch a video; the videos have
    the audio track and interactive demos in addition to the text and
    graphics of the slides, though.

    - anton

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Jan 16 17:38:03 2026
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    On 15-01-2026 13:04, Anton Ertl wrote:

    A few observations concerning the IMHO most interesting paper,
    "Code-Copying Compilation in Production":
    ...
    3. Commercial compilers (partly) using conventional compilers (see TF,
    fig. 4.7) - that was new to me;

    All Forth compilers I know work at the text interpretation level as
    the "Forth compiler" of Thinking Forth, Figure 4.7.

    4. GCC -O1 outperforming GCC -O3 on some benchmarks. That's new to me
    too. I might experiment with that one;

    I have analyzed it for bubblesort. There the problem is that gcc -O3 auto-vectorizes the pair of loads and the pair of stores (when the two
    elements are swapped). As a result, if a pair is stored in one
    iteration, the next iteration loads a pair that overlaps the
    previously stored pair. This means that the hardware cannot use its
    fast path in store-to-load forwarding, and leads to a huge slowdown.
    For a benchmark that has been around for over 40 years.

    In addition, the code generated by gcc -O3 also executes several
    additonal instructions per iteration, so I doubt that it would be
    faster even if the store-to-load forwarding problem did not exist.

    For fib, I have also looked at the generated code, but have not
    understood it well enough to see why the code generated by gcc -O3 is
    slower.

    - 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: https://forth-standard.org/
    EuroForth 2025 CFP: http://www.euroforth.org/ef25/cfp.html
    EuroForth 2025 registration: https://euro.theforth.net/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Fri Jan 16 23:10:24 2026
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    5. I added GCC extension support to 4tH in version 3.62.0. At the
    time, it improved performance by about 25%. By accident I found out
    that was no longer true. switch() based was faster. I didn't know
    there had been changes in that regard to GCC.

    If you mean the goto *a feature, these days you might try using tail
    calls instead. GCC and LLVM both now support a musttail attribute that
    ensures this optimization, or signals a compile-time error if it can't.

    https://lwn.net/Articles/1033373/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sat Jan 17 16:58:24 2026
    From Newsgroup: comp.lang.forth

    On 17-01-2026 08:10, Paul Rubin wrote:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    5. I added GCC extension support to 4tH in version 3.62.0. At the
    time, it improved performance by about 25%. By accident I found out
    that was no longer true. switch() based was faster. I didn't know
    there had been changes in that regard to GCC.

    If you mean the goto *a feature, these days you might try using tail
    calls instead. GCC and LLVM both now support a musttail attribute that ensures this optimization, or signals a compile-time error if it can't.

    https://lwn.net/Articles/1033373/

    Thanks for the article! But contrary to the Python interpreter, you
    could (thanks to some preprocessor magic) select how 4tH's VM would be compiled with NO changes to the source code whatsoever. That's why it
    could be reversed so easily by accident.

    The tail call method however, requires an entirely different VM. That's
    a lot of work for about 10% performance improvement - that may not even
    last for a single GCC update. And requires two VM's to maintain..

    So, I have to contemplate this carefully before putting work in it. But
    it's nice to know that I was not crazy noticing this ;-) And learning
    about a new GCC technique. :)

    Hans Bezemer

    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sat Jan 17 20:21:28 2026
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    The tail call method however, requires an entirely different
    VM. That's a lot of work for about 10% performance improvement - that
    may not even last for a single GCC update. And requires two VM's to maintain..

    You'd have to change the VM but on the other hand, it's a documented and supported feature of both GCC and Clang, and other compilers might get
    it too. I wouldn't worry about it vanishing with the next GCC update.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Jan 18 15:26:23 2026
    From Newsgroup: comp.lang.forth

    On 18-01-2026 05:21, Paul Rubin wrote:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    The tail call method however, requires an entirely different
    VM. That's a lot of work for about 10% performance improvement - that
    may not even last for a single GCC update. And requires two VM's to
    maintain..

    You'd have to change the VM but on the other hand, it's a documented and supported feature of both GCC and Clang, and other compilers might get
    it too. I wouldn't worry about it vanishing with the next GCC update.

    Well, the "goto" feature hasn't disappeared as well. It's just been
    nullified. Rendered useless. That's what I mean. And again? 10%? Really?

    Hans Bezemer
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Jan 18 16:34:50 2026
    From Newsgroup: comp.lang.forth

    In article <87wm1gpvdr.fsf@nightsong.com>,
    Paul Rubin <no.email@nospam.invalid> wrote:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    5. I added GCC extension support to 4tH in version 3.62.0. At the
    time, it improved performance by about 25%. By accident I found out
    that was no longer true. switch() based was faster. I didn't know
    there had been changes in that regard to GCC.

    If you mean the goto *a feature, these days you might try using tail
    calls instead. GCC and LLVM both now support a musttail attribute that >ensures this optimization, or signals a compile-time error if it can't.

    https://lwn.net/Articles/1033373/

    If you pass an address a as a tail call is it approximately equal
    to coroutines:

    : HEX: R> BASE @ >R >R HEX CO R> BASE ! ;

    Used for example as

    : .H HEX: . ;

    In this case the tail call is `` R> BASE ! '' to restore the base?

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Jan 18 22:17:45 2026
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    On 17-01-2026 08:10, Paul Rubin wrote:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    5. I added GCC extension support to 4tH in version 3.62.0. At the
    time, it improved performance by about 25%. By accident I found out
    that was no longer true. switch() based was faster. I didn't know
    there had been changes in that regard to GCC.

    You would have to look at the generated code. Which gcc version did
    you use? Certainly in my results on <http://www.complang.tuwien.ac.at/forth/threading/> switch usually is
    slower than direct or indirect threaded code.

    The tail call method however, requires an entirely different VM.

    It's also just a question of defining some macros appropriately.

    - 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: https://forth-standard.org/
    EuroForth 2025 CFP: http://www.euroforth.org/ef25/cfp.html
    EuroForth 2025 registration: https://euro.theforth.net/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From peter@peter.noreply@tin.it to comp.lang.forth on Mon Jan 19 23:26:35 2026
    From Newsgroup: comp.lang.forth

    On Fri, 16 Jan 2026 23:10:24 -0800
    Paul Rubin <no.email@nospam.invalid> wrote:

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    5. I added GCC extension support to 4tH in version 3.62.0. At the
    time, it improved performance by about 25%. By accident I found out
    that was no longer true. switch() based was faster. I didn't know
    there had been changes in that regard to GCC.

    If you mean the goto *a feature, these days you might try using tail
    calls instead. GCC and LLVM both now support a musttail attribute that ensures this optimization, or signals a compile-time error if it can't.

    https://lwn.net/Articles/1033373/

    I got interested to understand how tail calls could improve compared
    to computed gotos. So I took the five first "opcodes" from the VM in NTF64/LXF64 to compared the generated asm.
    The VM was written from the begining in X64 assembler (13 years ago)
    4 years ago I also implemented the VM i C to simplify porting to ARM64.
    At that time the asm version was about 10% faster then the generated
    C code, today the speed is about the same. C compilers have improved.
    It was implemented using computed gotos, usingthe following macro
    as the nesting code ending each "opcode"

    #define RELOAD() code=*ip++; goto *jmp_table[code]

    for the tail call version it was changed to

    RELOAD() opcode func=(opcode)tbl[*ip++]; __attribute__((musttail))
    return func(ip, tbl, TOP, FTOP, sp, rp, fp, lp)

    (line brooken to be readable)

    The noop "opcode has just the nesting and produces the following code

    movzx r9d, byte ptr [rcx]
    inc rcx
    jmp qword ptr [rax + 8*r9]

    and for the tailcall version

    movzx eax, byte ptr [r12]
    inc r12
    mov rax, qword ptr [r13 + 8*rax]
    rex64 jmp rax

    both compiled with
    clang -S -Wall -O2 -masm=intel -o vm8test3.asm vm8tail.c

    As I suspected the code is practically identical!

    It also turns out that the musttail attribute is not necessary
    It will generate a tailcall aanyway. The difference is that with
    musttail it will report an error if it cannot do the tailcall.

    Much more important is the __attribute__((preserve_none)) before
    each function. This indicated that more registers will be used to pass parameters. As seen above I pass 8 parameters to each function and
    they need to be in registers to match the asmbler written code.
    This is done automatically in the goto version as everything is in
    one function there.

    In the end it is more how you like to write your VM, as one function
    or one for each "opcode".

    Unfortunately GCC does not recognize preserve_none and uses the stack
    for some parameters

    Here is my test code

    // VM8 C variant using computed goto

    #include <stdint.h>

    #define UNS8 unsigned char
    #define INT64 long long int
    #define UNS64 unsigned long long int

    #define RELOAD() code=*ip++; goto *jmp_table[code]

    void VM8(UNS8 *ip, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) {

    const static void* jmp_table[] = {
    &&noop,
    &&swap,
    &&rot,
    &&eqzero,
    &&negate,
    };

    UNS8 code=*ip;
    UNS64 tmp;
    UNS64 TOP=*sp++;
    // double FTOP=*fp++;

    RELOAD();


    noop: // do nothing
    RELOAD();
    swap: // swap
    tmp=sp[0];
    sp[0]=TOP;
    TOP=tmp;
    RELOAD();
    rot: // rot
    tmp=TOP;
    TOP=sp[1];
    sp[1]=sp[0];
    sp[0]=tmp;
    RELOAD();
    eqzero: // 0=
    TOP=-(TOP==0);
    RELOAD();
    negate: // negate
    TOP=-TOP;
    RELOAD();


    } //vm8


    And here is the tail call version. Sorry for the long lines!

    // VM8 C variant using tailcalls

    #include <stdint.h>

    #define UNS8 unsigned char
    #define INT64 long long int
    #define UNS64 unsigned long long int


    typedef __attribute__((preserve_none)) void (*opcode) (UNS8*, UNS64*, UNS64, double, UNS64*, UNS64*, double*, UNS64*);

    #define RELOAD() opcode func=(opcode)tbl[*ip++]; __attribute__((musttail)) return func(ip, tbl, TOP, FTOP, sp, rp, fp, lp)

    #define FUNC __attribute__((preserve_none)) void

    FUNC noop(UNS8 *ip, UNS64 *tbl, UNS64 TOP, double FTOP, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) // do nothing
    {
    RELOAD();
    }

    FUNC swap(UNS8 *ip, UNS64 *tbl, UNS64 TOP, double FTOP, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) // swap
    {UNS64 tmp;
    tmp=sp[0];
    sp[0]=TOP;
    TOP=tmp;
    RELOAD();}

    FUNC rot(UNS8 *ip, UNS64 *tbl, UNS64 TOP, double FTOP, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) // rot
    {UNS64 tmp=TOP;
    TOP=sp[1];
    sp[1]=sp[0];
    sp[0]=tmp;
    RELOAD();}

    FUNC eqzero(UNS8 *ip, UNS64 *tbl, UNS64 TOP, double FTOP, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) // 0=
    {TOP=-(TOP==0);
    RELOAD();}

    FUNC negate(UNS8 *ip, UNS64 *tbl, UNS64 TOP, double FTOP, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) // negate
    {TOP=-TOP;
    RELOAD();}

    opcode jmp_table[]={
    noop,
    swap,
    rot,
    eqzero,
    negate,
    };



    void VM8(UNS8 *ip, UNS64 *sp, UNS64 *rp, double *fp, UNS64 *lp ) {


    UNS64 *tbl=(UNS64*)&jmp_table;
    UNS64 TOP=*sp++;
    double FTOP=*fp++;


    opcode func=(opcode)tbl[*ip++];
    func( ip, tbl, TOP, FTOP, sp, rp, fp, lp);

    }

    //vm8

    BR
    Peter




    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Mon Jan 19 15:22:07 2026
    From Newsgroup: comp.lang.forth

    peter <peter.noreply@tin.it> writes:
    for the tail call version it was changed to

    RELOAD() opcode func=(opcode)tbl[*ip++]; __attribute__((musttail))
    return func(ip, tbl, TOP, FTOP, sp, rp, fp, lp)


    You could possibly use "inline RELOAD() { .... ;}" instead of the macro.

    and for the tailcall version
    mov rax, qword ptr [r13 + 8*rax]
    rex64 jmp rax

    I wonder why the tailcall version didn't combine the mov with the jmp
    like the other version did.

    It also turns out that the musttail attribute is not necessary
    It will generate a tailcall aanyway. The difference is that with
    musttail it will report an error if it cannot do the tailcall.

    Yes, TCO has been present since the beginning but it's been
    opportunistic rather than something you can rely on.

    Unfortunately GCC does not recognize preserve_none and uses the stack
    for some parameters

    Oh that's interesting. I half remember there being some other feature
    for that, but who knows. Does -fwhole-program help?
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Tue Jan 20 00:33:00 2026
    From Newsgroup: comp.lang.forth

    peter <peter.noreply@tin.it> writes:
    // VM8 C variant using tailcalls ...
    #define FUNC __attribute__((preserve_none)) void

    Can you add static to that? It stops the symbol from being exported, so
    the compiler can omit the function call sequence when appropriate.

    I think -fwhole-program isn't likely to work so it wasn't a helpful
    suggestion, sorry.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Tue Jan 20 00:35:35 2026
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    If you pass an address a as a tail call is it approximately equal
    to coroutines:

    No I don't think so. The tail call is just a jump to that address
    (changes the program counter). A coroutine jump also has to change the
    stack pointer. See the section "Knuth's coroutines" here:

    https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

    Some Forths have a CO primitive that I think is similar. There is
    something like it on the Greenarrays processor.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From peter@peter.noreply@tin.it to comp.lang.forth on Tue Jan 20 10:44:40 2026
    From Newsgroup: comp.lang.forth

    On Mon, 19 Jan 2026 15:22:07 -0800
    Paul Rubin <no.email@nospam.invalid> wrote:

    peter <peter.noreply@tin.it> writes:
    for the tail call version it was changed to

    RELOAD() opcode func=(opcode)tbl[*ip++]; __attribute__((musttail))
    return func(ip, tbl, TOP, FTOP, sp, rp, fp, lp)


    You could possibly use "inline RELOAD() { .... ;}" instead of the macro.

    No that did not work. I also do not want the compiler to mess with this.
    The pre-processor expansion does exactly what I want.
    Musttail requires the parameters to exactly match on the incoming and
    outgoing calls. Like if it is a recursive call.



    and for the tailcall version
    mov rax, qword ptr [r13 + 8*rax]
    rex64 jmp rax

    I wonder why the tailcall version didn't combine the mov with the jmp
    like the other version did.

    I do also wonder about that! From my previous testing it will not make a difference speed-wise.


    It also turns out that the musttail attribute is not necessary
    It will generate a tailcall aanyway. The difference is that with
    musttail it will report an error if it cannot do the tailcall.

    Yes, TCO has been present since the beginning but it's been
    opportunistic rather than something you can rely on.

    Unfortunately GCC does not recognize preserve_none and uses the stack
    for some parameters

    It looks like it recognizes it but choose to ignore it.
    That is what the warning messages say.


    Oh that's interesting. I half remember there being some other feature
    for that, but who knows. Does -fwhole-program help?

    I will for sure continue to use the computed goto also in the future.
    The complete VM8 function containing 157 opcodes is about 1200
    lines of code. 255 are for the function-array. that leaves 945 lines
    for 157 opcode, about 6 lines per opcode!

    BR
    Peter

    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Jan 20 12:12:44 2026
    From Newsgroup: comp.lang.forth

    In article <87bjioptpk.fsf@nightsong.com>,
    Paul Rubin <no.email@nospam.invalid> wrote:
    albert@spenarnc.xs4all.nl writes:
    If you pass an address a as a tail call is it approximately equal
    to coroutines:

    No I don't think so. The tail call is just a jump to that address
    (changes the program counter). A coroutine jump also has to change the
    stack pointer. See the section "Knuth's coroutines" here:

    Which stack pointer do you mean? The data stack pointer or the
    return stack pointer?
    Where is the program to continue after performing the tail call?
    Probably the same if the tail call was not present.

    Pushing a address on the return stack, then continue interpreting
    is tantamount to a jump.


    https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

    Some Forths have a CO primitive that I think is similar. There is
    something like it on the Greenarrays processor.

    You can see the CO primitive used in the example. The CO name is
    original by me, Chuck Moore uses ;: , not implying they are exactly
    the same.

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Tue Jan 20 22:17:45 2026
    From Newsgroup: comp.lang.forth

    peter <peter.noreply@tin.it> writes:
    On Fri, 16 Jan 2026 23:10:24 -0800
    Paul Rubin <no.email@nospam.invalid> wrote:
    The VM was written from the begining in X64 assembler (13 years ago)
    4 years ago I also implemented the VM i C to simplify porting to ARM64.
    At that time the asm version was about 10% faster then the generated
    C code, today the speed is about the same. C compilers have improved.

    My impression is that they have not really improved in decades, for
    the kinds of code in Gforth (and, I guess NTF64/LXF64). Except that
    we can now use one or two registers more on AMD64 if we do things
    right.

    Much more important is the __attribute__((preserve_none)) before
    each function. This indicated that more registers will be used to pass >parameters. As seen above I pass 8 parameters to each function and
    they need to be in registers to match the asmbler written code.
    This is done automatically in the goto version as everything is in
    one function there.

    In the end it is more how you like to write your VM, as one function
    or one for each "opcode".

    Unfortunately GCC does not recognize preserve_none and uses the stack
    for some parameters

    With gcc you can use explicit register variables instead.

    In any case, the tail-calling technique is not as portable as I would
    like. Depending on the compiler and ABI/architecture, one wants to
    pass more or fewer VM registers as parameters, and maybe deal with the
    rest with explicit register variables. Sure, we can find ways to
    parameterize this stuff so the main body of the code does not see the difference, but working on a new architecture out of the box will
    either not work or require a lot of work.

    - 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: https://forth-standard.org/
    EuroForth 2025 CFP: http://www.euroforth.org/ef25/cfp.html
    EuroForth 2025 registration: https://euro.theforth.net/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Tue Jan 20 22:36:05 2026
    From Newsgroup: comp.lang.forth

    Paul Rubin <no.email@nospam.invalid> writes:
    peter <peter.noreply@tin.it> writes:
    and for the tailcall version
    mov rax, qword ptr [r13 + 8*rax]
    rex64 jmp rax

    I wonder why the tailcall version didn't combine the mov with the jmp
    like the other version did.

    I always wonder about that when I see the code generated by gcc for
    goto *. With any gcc since 3.0, I see direct-threaded dispatch
    compiled to code like:

    add $0x8,%rbx
    mov (%rbx),%rax
    jmp *%rax

    GCC-2.95 and earlier know how to combine the last two instructions into

    jmp (%rbx)

    Yes, TCO has been present since the beginning but it's been
    opportunistic rather than something you can rely on.

    I tried to use tail-call optimization for threaded-code dispatch in
    gcc in 1995, and even described it as theoretical possibility
    [ertl95pldi], but gcc of that time did not tail-call optimize code
    like that shown by Peter.

    @InProceedings{ertl95pldi,
    author = "M. Anton Ertl",
    title = "Stack Caching for Interpreters",
    booktitle = "SIGPLAN Conference on Programming Language
    Design and Implementation (PLDI'95)",
    year = "1995",
    crossref = "sigplan95",
    pages = "315--327",
    url = "https://www.complang.tuwien.ac.at/papers/ertl95pldi.ps.gz",
    abstract = "An interpreter can spend a significant part of its
    execution time on arguments of virtual machine
    instructions. This paper explores two methods to
    reduce this overhead for virtual stack machines by
    caching top-of-stack values in (real machine)
    registers. The {\em dynamic method} is based on
    having, for every possible state of the cache, one
    specialized version of the whole interpreter; the
    execution of an instruction usually changes the
    state of the cache and the next instruction is
    executed in the version corresponding to the new
    state. In the {\em static method} a state machine
    that keeps track of the cache state is added to the
    compiler. Common instructions exist in specialized
    versions for several states, but it is not necessary
    to have a version of every instruction for every
    cache state. Stack manipulation instructions are
    optimized away."
    }

    Unfortunately GCC does not recognize preserve_none and uses the stack
    for some parameters

    Oh that's interesting. I half remember there being some other feature
    for that, but who knows.

    Explicit register variables.

    Does -fwhole-program help?

    Unlikely. How should it?

    - 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: https://forth-standard.org/
    EuroForth 2025 CFP: http://www.euroforth.org/ef25/cfp.html
    EuroForth 2025 registration: https://euro.theforth.net/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Thu Jan 22 16:51:13 2026
    From Newsgroup: comp.lang.forth

    On 16-01-2026 18:38, Anton Ertl wrote:

    On 17-01-2026 16:58, Hans Bezemer wrote:

    I've done my thing, compiled 4tH with optimizations -O3 till -O0.
    I thought, let's make this simple and execute ALL benchmarks I got. Some
    of them have become useless, though for the simple reason hardware has
    become that much better.

    But still, here it is. Overall, the performance consistently
    deteriorates, aka -O3 gives the best performance. There are a few minor glitches, some due to random benchmark data.

    For those curious, this is a European CSV with all the data. BTW, you
    can find all benchmarks here: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/bench/

    Hans Bezemer

    ---8<---
    Benchmark;-O3;-O2;-O1;-O0
    bench.4th;6.79;6.36;6.68;6.33
    benchm.4th;1.21;1.66;1.86;2.8
    benchxls.4th;0.06;0.08;0.08;0.12
    bubble.4th;0.69;0.95;0.96;1.72
    bytesiev.4th;0.01;0.01;0.01;0.02
    countbit.4th;3.52;4.76;5.02;8.01
    cowell.4th;15.15;20.2;18.91;31.29
    fib.4th;0.79;1.02;1.02;1.72
    isortest.4th;0.23;0.33;0.31;0.56
    matrix.4th;0.22;0.31;0.3;0.51
    misty.4th;0.58;0.84;1.01;1.59
    pforth.4th;10.47;13.55;14.42;22.68
    prims.4th;5.96;8;8.59;14.28
    simple.4th;0.5;0.7;0.82;1.21
    sortest.4th;140.96;163.68;150.17;270.87
    thread.4th;0.35;0.41;0.49;0.7
    ---8<---

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    On 15-01-2026 13:04, Anton Ertl wrote:

    A few observations concerning the IMHO most interesting paper,
    "Code-Copying Compilation in Production":
    ...
    3. Commercial compilers (partly) using conventional compilers (see TF,
    fig. 4.7) - that was new to me;

    All Forth compilers I know work at the text interpretation level as
    the "Forth compiler" of Thinking Forth, Figure 4.7.

    4. GCC -O1 outperforming GCC -O3 on some benchmarks. That's new to me
    too. I might experiment with that one;

    I have analyzed it for bubblesort. There the problem is that gcc -O3 auto-vectorizes the pair of loads and the pair of stores (when the two elements are swapped). As a result, if a pair is stored in one
    iteration, the next iteration loads a pair that overlaps the
    previously stored pair. This means that the hardware cannot use its
    fast path in store-to-load forwarding, and leads to a huge slowdown.
    For a benchmark that has been around for over 40 years.

    In addition, the code generated by gcc -O3 also executes several
    additonal instructions per iteration, so I doubt that it would be
    faster even if the store-to-load forwarding problem did not exist.

    For fib, I have also looked at the generated code, but have not
    understood it well enough to see why the code generated by gcc -O3 is
    slower.

    - anton

    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Jan 24 11:28:30 2026
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    I've done my thing, compiled 4tH with optimizations -O3 till -O0.
    I thought, let's make this simple and execute ALL benchmarks I got. Some
    of them have become useless, though for the simple reason hardware has >become that much better.

    But still, here it is. Overall, the performance consistently
    deteriorates, aka -O3 gives the best performance.

    Which compiler and which hardware?

    For a random program, I would expect higher optimization levels to
    produe faster code. For a Forth system and these recent gccs, the auto-vectorization of adjacent memory accesses may lead to similar
    problems as in the C bubble-sort benchmark. In Gforth, this actually
    happens unless we disable vectorization (which we normally do), and,
    moreover, with the vectorized code, gcc introduces additional
    inefficiencies (see below).

    Here's the output of ./gforth-fast onebench.fs compiled from the
    current development version with gcc-12.2 and running on a Ryzen 5800X
    (numbers are times, lower is better):

    sieve bubble matrix fib fft gcc options
    0.025 0.023 0.013 0.033 0.016 -O2
    0.025 0.023 0.013 0.037 0.016 -O3 -fno-tree-vectorize (gforth default)
    0.404 0.418 0.377 0.472 0.244 -O3 (with auto vectorization)
    0.145 0.122 0.124 0.122 0.073 gforth default, using --no-dynamic

    So how is the code different? Here's the code for ROT:


    -O3 (auto-vectorized) -O3 -fno-tree-vec... -O2
    add $0x8,%rbx add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r10),%xmm1 mov 0x8(%r10),%rdx mov 0x8(%r10),%rdx
    mov 0x10(%r10),%rcx mov 0x10(%r10),%rax mov 0x10(%r10),%rax
    punpcklqdq %xmm1,%xmm1 mov %r13,0x8(%r10) mov %r13,0x8(%r10)
    punpckhqdq %xmm1,%xmm0 mov %rdx,0x10(%r10) mov %rdx,0x10(%r10)
    movups %xmm0,0x8(%r10) mov %rax,%r13 mov %rax,%r13
    mov (%rbx),%rax mov (%rbx),%rax mov (%rbx),%rax
    mov %r14,0x8(%rsp) jmp *%rax jmp *%rax
    mov %rax,%r11
    mov %r15,%r9
    mov %rcx,0x10(%rsp)
    jmp 0x55bff2a58a99

    So in this case -O3 without auto-vectorization generates the same code
    as -O2. Auto-vectorization, OTOH, replaces

    mov 0x8(%r10),%rdx
    mov 0x10(%r10),%rax

    with

    movq 0x8(%r10),%xmm1

    and then performs the rotation with the punpck instructions, finally
    storing two cells into memory with movups. For some reason it also
    separately loads 0x10(%r10) into %rcx (instead of extracting it from
    %xmm1), and eventually stores it to 0x10(%rsp), which seems to be one
    of the locations of the TOS.

    I expect that gcc's auto-vectorization will do similar things to
    primitives like ROT 2! 2SWAP (all of which are hit in gforth) in other
    Forth systems with a C substrate, because they all tend to access two
    (or more) adjacent cells.

    But the big hit with the auto-vectorized code is not these changes,
    but what happens at the end of the primitive: without
    auto-vectorization there is the indirect jump of the threaded-code
    dispatch, but with auto-vectorization it jumps to 0x55bff2a58a99:

    0x000055bff2a58a99 <gforth_engine2+153>: movq 0x8(%rsp),%xmm0
    0x000055bff2a58a9f <gforth_engine2+159>: movq %r9,%xmm1
    0x000055bff2a58aa4 <gforth_engine2+164>: movhps 0x8(%rsp),%xmm1
    0x000055bff2a58aa9 <gforth_engine2+169>: movhps 0x10(%rsp),%xmm0
    0x000055bff2a58aae <gforth_engine2+174>: movhlps %xmm0,%xmm5
    0x000055bff2a58ab1 <gforth_engine2+177>: movq %xmm0,%r14
    0x000055bff2a58ab6 <gforth_engine2+182>: movq %xmm1,%r15
    0x000055bff2a58abb <gforth_engine2+187>: movhps %xmm1,0x18(%rsp)
    0x000055bff2a58ac0 <gforth_engine2+192>: movq %xmm5,%r8
    0x000055bff2a58ac5 <gforth_engine2+197>: mov %r15,%rdi
    0x000055bff2a58ac8 <gforth_engine2+200>: mov %r14,%rsi
    0x000055bff2a58acb <gforth_engine2+203>: mov %r8,%rcx
    0x000055bff2a58ace <gforth_engine2+206>: jmp *%r11

    We can see here that, among other things 0x10(%rsp) (the TOS) is
    loaded into %xmm0 and then moved through %xmm5 into %r8 and the %rcx,
    as well as through %r14 into %rsi so at the end TOS resides in all
    those places. And I see that other primitives expect the TOS in some
    of those places, e.g. 1+:

    -O3 (auto-vectorized) -O3 -fno-tree-vec...
    add $0x8,%rbx add $0x8,%rbx
    lea 0x1(%r8),%rcx add $0x1,%r13
    mov (%rbx),%rax mov (%rbx),%rax
    mov %r14,0x8(%rsp) jmp *%rax
    mov %rax,%r11
    mov %r15,%r9
    mov %rcx,0x10(%rsp)
    jmp 0x55bff2a58a99

    Jumping to 0x55bff2a58a99 instead of performing an indirect jump
    disables dynamic native code generation in Gforth and all the
    optimizations that are based on it. You can see in the --no-dynamic
    line how much that costs. The remaining factor of 3 is probably due
    to the large number of additional instructions that are performed in
    the auto-vectorized engine.

    What is the 4th code for ROT with -O2 and -O3?

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Jan 24 16:47:16 2026
    From Newsgroup: comp.lang.forth

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    I've done my thing, compiled 4tH with optimizations -O3 till -O0.
    I thought, let's make this simple and execute ALL benchmarks I got. Some >>of them have become useless, though for the simple reason hardware has >>become that much better.

    But still, here it is. Overall, the performance consistently
    deteriorates, aka -O3 gives the best performance.

    Which compiler and which hardware?

    For a random program, I would expect higher optimization levels to
    produe faster code. For a Forth system and these recent gccs, the >auto-vectorization of adjacent memory accesses may lead to similar
    problems as in the C bubble-sort benchmark. In Gforth, this actually
    happens unless we disable vectorization (which we normally do), and, >moreover, with the vectorized code, gcc introduces additional
    inefficiencies (see below).

    Here's the output of ./gforth-fast onebench.fs compiled from the
    current development version with gcc-12.2 and running on a Ryzen 5800X >(numbers are times, lower is better):

    sieve bubble matrix fib fft gcc options
    0.025 0.023 0.013 0.033 0.016 -O2
    0.025 0.023 0.013 0.037 0.016 -O3 -fno-tree-vectorize (gforth default) 0.404 0.418 0.377 0.472 0.244 -O3 (with auto vectorization)
    0.145 0.122 0.124 0.122 0.073 gforth default, using --no-dynamic

    I have now also tried it with gcc-14.2, and that produces better code.
    Results from a Xeon E-2388G (Rocket Lake):

    sieve bubble matrix fib fft gcc options
    0.032 0.032 0.015 0.037 0.014 -O2
    0.035 0.032 0.015 0.037 0.014 -O3 -fno-tree-vectorize (gforth default)
    0.033 0.034 0.016 0.032 0.014 -O3 (with auto vectorization)

    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax

    And the common tail with all these move instructions is gone.

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From peter@peter.noreply@tin.it to comp.lang.forth on Sun Jan 25 23:31:10 2026
    From Newsgroup: comp.lang.forth

    On Sat, 24 Jan 2026 16:47:16 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    I've done my thing, compiled 4tH with optimizations -O3 till -O0.
    I thought, let's make this simple and execute ALL benchmarks I got. Some >>of them have become useless, though for the simple reason hardware has >>become that much better.

    But still, here it is. Overall, the performance consistently >>deteriorates, aka -O3 gives the best performance.

    Which compiler and which hardware?

    For a random program, I would expect higher optimization levels to
    produe faster code. For a Forth system and these recent gccs, the >auto-vectorization of adjacent memory accesses may lead to similar
    problems as in the C bubble-sort benchmark. In Gforth, this actually >happens unless we disable vectorization (which we normally do), and, >moreover, with the vectorized code, gcc introduces additional >inefficiencies (see below).

    Here's the output of ./gforth-fast onebench.fs compiled from the
    current development version with gcc-12.2 and running on a Ryzen 5800X >(numbers are times, lower is better):

    sieve bubble matrix fib fft gcc options
    0.025 0.023 0.013 0.033 0.016 -O2
    0.025 0.023 0.013 0.037 0.016 -O3 -fno-tree-vectorize (gforth default) 0.404 0.418 0.377 0.472 0.244 -O3 (with auto vectorization)
    0.145 0.122 0.124 0.122 0.073 gforth default, using --no-dynamic

    I have now also tried it with gcc-14.2, and that produces better code. Results from a Xeon E-2388G (Rocket Lake):

    sieve bubble matrix fib fft gcc options
    0.032 0.032 0.015 0.037 0.014 -O2
    0.035 0.032 0.015 0.037 0.014 -O3 -fno-tree-vectorize (gforth default)
    0.033 0.034 0.016 0.032 0.014 -O3 (with auto vectorization)

    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax

    And the common tail with all these move instructions is gone.

    - anton

    What does your C code looks like? I could not get clang or gcc to auto vectories
    with my existing code

    UNS64 *tmp64 = (UNS64*)TOP;
    tmp64[0] = sp[0];
    tmp64[1] = sp[1];
    TOP = sp[2];
    sp += 3;


    In the end I changed my code to tell the compiler that it is a vector with

    typedef UNS64 v2u64 __attribute__((vector_size(16))) __attribute__((aligned(8)));

    and
    *(v2u64*)TOP = *(v2u64*)sp;
    TOP=sp[2];
    sp=sp+3;

    this will produce

    vmovups xmm0, xmmword ptr [rdx]
    vmovups xmmword ptr [r8], xmm0
    mov r8, qword ptr [rdx + 16]
    add rdx, 24

    movzx r9d, byte ptr [rcx] // nesting code
    inc rcx
    jmp qword ptr [rax + 8*r9]

    But also using memcpy((UNS64*)TOP, (UNS64*)sp,16); gives the same code!

    Looks like it is working also in ARM64
    BR
    Peter

    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Mon Jan 26 19:24:43 2026
    From Newsgroup: comp.lang.forth

    peter <peter.noreply@tin.it> writes:
    On Sat, 24 Jan 2026 16:47:16 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
    I have now also tried it with gcc-14.2, and that produces better code.
    Results from a Xeon E-2388G (Rocket Lake):

    sieve bubble matrix fib fft gcc options
    0.032 0.032 0.015 0.037 0.014 -O2
    0.035 0.032 0.015 0.037 0.014 -O3 -fno-tree-vectorize (gforth default)
    0.033 0.034 0.016 0.032 0.014 -O3 (with auto vectorization)

    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax

    And the common tail with all these move instructions is gone.

    - anton

    What does your C code looks like? I could not get clang or gcc to auto vectories
    with my existing code

    UNS64 *tmp64 = (UNS64*)TOP;
    tmp64[0] = sp[0];
    tmp64[1] = sp[1];
    TOP = sp[2];
    sp += 3;

    Gforth's source code for 2! is:

    2! ( w1 w2 a_addr -- ) core two_store
    ""Store @i{w2} into the cell at @i{c-addr} and @i{w1} into the next cell."" a_addr[0] = w2;
    a_addr[1] = w1;

    A generator produces the following from that, which is passed to gcc:

    LABEL(two_store) /* 2! ( w1 w2 a_addr -- ) S1 -- S1 */
    /* Store @i{w2} into the cell at @i{c-addr} and @i{w1} into the next cell. */ NAME("2!")
    ip += 1;
    LABEL1(two_store)
    {
    DEF_CA
    MAYBE_UNUSED Cell w1;
    MAYBE_UNUSED Cell w2;
    MAYBE_UNUSED Cell * a_addr;
    NEXT_P0;
    vm_Cell2w(sp[2],w1);
    vm_Cell2w(sp[1],w2);
    vm_Cell2a_(spTOS,a_addr);
    #ifdef VM_DEBUG
    if (vm_debug) {
    fputs(" w1=", vm_out); printarg_w(w1);
    fputs(" w2=", vm_out); printarg_w(w2);
    fputs(" a_addr=", vm_out); printarg_a_(a_addr);
    }
    #endif
    sp += 3;
    {
    #line 1815 "prim"
    a_addr[0] = w2;
    a_addr[1] = w1;
    #line 10136 "prim-fast.i"
    }

    #ifdef VM_DEBUG
    if (vm_debug) {
    fputs(" -- ", vm_out); fputc('\n', vm_out);
    }
    #endif
    NEXT_P1;
    spTOS = sp[0];
    LABEL2(two_store)
    NAME1("l2-two_store")
    NEXT_P1_5;
    LABEL3(two_store)
    NAME1("l3-two_store")
    DO_GOTO;
    }

    There are a lot of macros in this code, and I fear that expanding them
    makes the code even less readable, but the essence for the
    auto-vectorized part is something like:

    w1 = sp[2];
    w2 = sp[1];
    a_addr = spTOS;
    sp += 3;
    a_addr[0] = w2;
    a_addr[1] = w1;
    spTOS = sp[0];

    My guess is that in your code the compiler expected that sp[1] might
    alias with tmp64[0], and therefore did not vectorize the loads and the
    stores, whereas in the Gforth code, the loads both happen first, and
    then the two stores, and gcc can vectorize that. I doubt that there
    is a big benefit from that, though.

    typedef UNS64 v2u64 __attribute__((vector_size(16))) __attribute__((aligned(8)));

    I'll have to remember the aligned attribute for future games with gcc
    explicit vectorization.

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From peter@peter.noreply@tin.it to comp.lang.forth on Tue Jan 27 15:44:55 2026
    From Newsgroup: comp.lang.forth

    On Mon, 26 Jan 2026 19:24:43 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

    peter <peter.noreply@tin.it> writes:
    On Sat, 24 Jan 2026 16:47:16 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
    I have now also tried it with gcc-14.2, and that produces better code.
    Results from a Xeon E-2388G (Rocket Lake):

    sieve bubble matrix fib fft gcc options
    0.032 0.032 0.015 0.037 0.014 -O2
    0.035 0.032 0.015 0.037 0.014 -O3 -fno-tree-vectorize (gforth default) >> 0.033 0.034 0.016 0.032 0.014 -O3 (with auto vectorization)

    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax

    And the common tail with all these move instructions is gone.

    - anton

    What does your C code looks like? I could not get clang or gcc to auto vectories
    with my existing code

    UNS64 *tmp64 = (UNS64*)TOP;
    tmp64[0] = sp[0];
    tmp64[1] = sp[1];
    TOP = sp[2];
    sp += 3;

    Gforth's source code for 2! is:

    2! ( w1 w2 a_addr -- ) core two_store
    ""Store @i{w2} into the cell at @i{c-addr} and @i{w1} into the next cell."" a_addr[0] = w2;
    a_addr[1] = w1;

    A generator produces the following from that, which is passed to gcc:

    LABEL(two_store) /* 2! ( w1 w2 a_addr -- ) S1 -- S1 */
    /* Store @i{w2} into the cell at @i{c-addr} and @i{w1} into the next cell. */ NAME("2!")
    ip += 1;
    LABEL1(two_store)
    {
    DEF_CA
    MAYBE_UNUSED Cell w1;
    MAYBE_UNUSED Cell w2;
    MAYBE_UNUSED Cell * a_addr;
    NEXT_P0;
    vm_Cell2w(sp[2],w1);
    vm_Cell2w(sp[1],w2);
    vm_Cell2a_(spTOS,a_addr);
    #ifdef VM_DEBUG
    if (vm_debug) {
    fputs(" w1=", vm_out); printarg_w(w1);
    fputs(" w2=", vm_out); printarg_w(w2);
    fputs(" a_addr=", vm_out); printarg_a_(a_addr);
    }
    #endif
    sp += 3;
    {
    #line 1815 "prim"
    a_addr[0] = w2;
    a_addr[1] = w1;
    #line 10136 "prim-fast.i"
    }

    #ifdef VM_DEBUG
    if (vm_debug) {
    fputs(" -- ", vm_out); fputc('\n', vm_out);
    }
    #endif
    NEXT_P1;
    spTOS = sp[0];
    LABEL2(two_store)
    NAME1("l2-two_store")
    NEXT_P1_5;
    LABEL3(two_store)
    NAME1("l3-two_store")
    DO_GOTO;
    }

    There are a lot of macros in this code, and I fear that expanding them
    makes the code even less readable, but the essence for the
    auto-vectorized part is something like:

    w1 = sp[2];
    w2 = sp[1];
    a_addr = spTOS;
    sp += 3;
    a_addr[0] = w2;
    a_addr[1] = w1;
    spTOS = sp[0];

    My guess is that in your code the compiler expected that sp[1] might
    alias with tmp64[0], and therefore did not vectorize the loads and the stores, whereas in the Gforth code, the loads both happen first, and
    then the two stores, and gcc can vectorize that. I doubt that there
    is a big benefit from that, though.

    Yes that was it. changing to:

    UNS64 *tmp64 = (UNS64*)TOP;
    UNS64 d0=sp[0];
    UNS64 d1=sp[1];
    tmp64[0] = d0;
    tmp64[1] = d1;
    TOP = sp[2];
    sp += 3;

    made the compiler (clang-21 in this case) generate the expected code



    typedef UNS64 v2u64 __attribute__((vector_size(16))) __attribute__((aligned(8)));

    I'll have to remember the aligned attribute for future games with gcc explicit vectorization.

    Without that it will generate the opcodes that needs 16 byte alignment

    BR
    Peter

    - anton


    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Jan 29 18:27:12 2026
    From Newsgroup: comp.lang.forth

    peter <peter.noreply@tin.it> writes:
    On Mon, 26 Jan 2026 19:24:43 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

    peter <peter.noreply@tin.it> writes:
    On Sat, 24 Jan 2026 16:47:16 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax
    ...
    UNS64 *tmp64 = (UNS64*)TOP;
    UNS64 d0=sp[0];
    UNS64 d1=sp[1];
    tmp64[0] = d0;
    tmp64[1] = d1;
    TOP = sp[2];
    sp += 3;

    made the compiler (clang-21 in this case) generate the expected code

    The auto-vectorized implementation of 2! above should perform ok,
    because it loads each stack item separately, and the wide movups is
    only used for the stores. If there is a wide load from the stack
    involved, I expect a significant slowdown, because the stack items
    usually have been stored recently, and narrow-store-to-wide-load
    forwarding is a slow path on recent (and presumably also older) CPU
    cores: https://www.complang.tuwien.ac.at/anton/stwlf/

    typedef UNS64 v2u64 __attribute__((vector_size(16))) __attribute__((aligned(8)));

    I'll have to remember the aligned attribute for future games with gcc
    explicit vectorization.

    Without that it will generate the opcodes that needs 16 byte alignment

    Yes. Until now I worked around that by using memcpy to a vector
    variable, but this approach is much more convenient.

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Jan 30 13:20:35 2026
    From Newsgroup: comp.lang.forth

    In article <2026Jan29.192712@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    peter <peter.noreply@tin.it> writes:
    On Mon, 26 Jan 2026 19:24:43 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

    peter <peter.noreply@tin.it> writes:
    On Sat, 24 Jan 2026 16:47:16 GMT
    anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
    The code for ROT and 2SWAP does not use auto-vectorization, and the
    code for 2! uses auto-vectorization in a way that reduces the
    instruction count:

    -O3 (auto-vectorized) -O3 -fno-tree-vectorize
    add $0x8,%rbx add $0x8,%rbx
    movq 0x8(%r13),%xmm0 mov 0x10(%r13),%rax
    add $0x18,%r13 mov 0x8(%r13),%rdx
    movhps -0x8(%r13),%xmm0 add $0x18,%r13
    movups %xmm0,(%r8) mov %rdx,(%r8)
    mov 0x0(%r13),%r8 mov %rax,0x8(%r8)
    mov (%rbx),%rax mov 0x0(%r13),%r8
    jmp *%rax mov (%rbx),%rax
    jmp *%rax
    ...
    UNS64 *tmp64 = (UNS64*)TOP;
    UNS64 d0=sp[0];
    UNS64 d1=sp[1];
    tmp64[0] = d0;
    tmp64[1] = d1;
    TOP = sp[2];
    sp += 3;

    made the compiler (clang-21 in this case) generate the expected code

    The auto-vectorized implementation of 2! above should perform ok,
    because it loads each stack item separately, and the wide movups is
    only used for the stores. If there is a wide load from the stack
    involved, I expect a significant slowdown, because the stack items
    usually have been stored recently, and narrow-store-to-wide-load
    forwarding is a slow path on recent (and presumably also older) CPU
    cores: https://www.complang.tuwien.ac.at/anton/stwlf/

    typedef UNS64 v2u64 __attribute__((vector_size(16))) __attribute__((aligned(8)));

    I'll have to remember the aligned attribute for future games with gcc
    explicit vectorization.

    Without that it will generate the opcodes that needs 16 byte alignment

    Yes. Until now I worked around that by using memcpy to a vector
    variable, but this approach is much more convenient.

    I always wonder, is this relevant to the industrial applications of
    gforth or gforth based programs that are sold commercially?


    - anton
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Jan 30 18:00:31 2026
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    I always wonder, is this relevant to the industrial applications of
    gforth or gforth based programs that are sold commercially?

    Are there any Gforth-based programs that are sold commercially?
    Concerning industrial applications, the only ones I know about have to
    do with Open Firmware, and I doubt that those care much about the
    performance of Gforth. But there are probably industrial applications
    (maybe even commercial programs) that use Gforth that I do not know
    about. If one of the IBM users had not contacted us when he left the
    group, I would not know about the application of Gforth within IBM.

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21b-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Thu Apr 2 20:59:39 2026
    From Newsgroup: comp.lang.forth

    On 20/01/2026 08:35, Paul Rubin wrote:
    albert@spenarnc.xs4all.nl writes:
    If you pass an address a as a tail call is it approximately equal
    to coroutines:

    No I don't think so. The tail call is just a jump to that address
    (changes the program counter). A coroutine jump also has to change the
    stack pointer. See the section "Knuth's coroutines" here:

    https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

    Some Forths have a CO primitive that I think is similar. There is
    something like it on the Greenarrays processor.

    Never having looked at coroutines before I tried implementing the
    examples in the above paper. The resulting code is:

    -1 constant EOF

    : get-char ( ca u -- ca' u' [ch | EOF] )
    ?dup 0= if drop EOF exit then
    over c@ >r 1 /string r>
    ;

    : is-alpha ( ch -- f ) 'a' 'z' 1+ within ; \ adequate for testing

    create token 32 chars allot
    2variable tok

    : init-token ( ca u ) token 0 tok 2! ;

    : add-to-token ( ch -- ) tok 2@ + c! 1 tok +! ;

    : got-token ( type -- )
    cr if ." Word: " else ." Punct: " then
    tok 2@ type
    init-token
    ;

    : ?got-token ( ca u ) \ To handle tokens left in the buffer e.g. on EOF
    tok @ if 1 got-token then \ Only needed for WORD tokens
    ;

    \ The consumer
    : parser ( ch -- )
    dup is-alpha
    if
    begin
    add-to-token exit
    [:] parser.alpha ( ch2 ) \ Re-enter here
    dup is-alpha 0=
    until
    then
    ?got-token
    add-to-token
    0 got-token ( Punctuation token )
    exit
    [:] parser.end
    ?got-token
    ;

    \ The producer
    : decompressor ( ca u -- )
    init-token
    begin
    get-char ( -- ca'u' ch ) \ or ( -- EOF )
    dup EOF =
    if drop parser.end cr ." End of file" cr exit then
    dup
    while
    dup $FF =
    if drop get-char >r get-char ( -- ca' u' ch ) ( R: -- len )
    dup parser r> 1
    ?do dup parser.alpha loop
    drop
    else
    parser
    then
    repeat
    ;

    init-token
    s\" \xFF\x03abc%\xFF\x02-&xyz@qwerty" decompressor .s
    \ Displays
    Word: aaabc
    Punct: %
    Punct: -
    Punct: -
    Punct: &
    Word: xyz
    Punct: @
    Word: qwerty
    End of file

    Switching between the routines is achieved by calls to different entry
    points in the Parser, and by EXIT or ; back to the decompressor. This is
    not Standard Forth and uses an extension that I implemented over 10
    years ago, tested but never used. I cannot remember my motivation for
    doing so perhaps somebody mentioned it as an idea. I'd be pleased if
    somebody could point to any previous use of this technique.

    This extension is a word called [:] that behaves like : and can only be
    used in the middle of a standard colon definition. Usage e.g.
    : foo ... [:] bar ... [:] baz ... ;
    to create named entry points into colon definition FOO.
    Such an entry definition compiles no executable code of its own and
    execution of the enclosing definition simply executes the body of the definition as if the alternative entry points weren't there e.g.
    : foo 1 . [:] bar 2 . [:] baz 3 . ;
    foo 1 2 3
    executing the alternative entry points executes the code following
    definition of the entry point e.g.
    bar 2 3
    baz 3
    Using BAR etc in another colon definition calls that entry point just
    like any standard colon definition to run the code following that entry
    point.
    An entry point does not use the control stack in any way, therefore it
    can be positioned inside any control structure.
    An entry point becomes visible immediately its definition is complete,
    so it can be called from anywhere in the rest of the enclosing definition.
    As a pseudo colon definition an entry point has an execution token that
    can be obtained or used by the usual set of words such as ' POSTPONE etc. Execution of code following an entry point can be terminated at any time
    using EXIT

    In the example above in addition to PARSER there are two other entry
    points PARSER.ALPHA (in the middle of a loop) and PARSER.END

    There are other uses for [:] entry points:
    1. Coroutines (see example above)

    2. Recursion by name e.g.
    : foo ... [:] bar ... bar ...; \ recurses to BAR or
    : foo [foo] ... foo ... ;
    The second example can be achieved by using SYNONYM
    e.g. SYNONYM FOO RECURSE but the first can include initialisation

    3. Obtain the xt of the current definition, which has been requested a
    few times on c.l.f e.g.
    : x [:] my-xt ['] my-xt ... ; \ Removes the need for LATEST

    4. Generators akin to those of Python with next e.g.
    variable n : foo n ! exit [:] foo.next n @ 1 n +! ;
    1 foo
    foo.next ( -- 1 )
    foo.next ( -- 2 )

    5. Debugging by inserting entry points at which a definition can be run
    with known test data on the stack

    6. Nested colon definitions e.g. a possible use - unsure of its utility.
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    b 2 3
    b is effectively a nested colon definition - forbidden by the standard
    --
    Gerry

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sat Apr 4 18:02:10 2026
    From Newsgroup: comp.lang.forth

    Gerry Jackson <do-not-use@swldwa.uk> writes:
    Never having looked at coroutines before I tried implementing the
    examples in the above paper. The resulting code is: ...

    It would take me a while to understand that, but [:] is cool (I haven't
    seen it before), and it lets you do something similar to protothreads.

    For coroutines in general you should also read this:

    https://doi.org/10.1145/1462166.1462167

    It discusses "stackful" coroutines where each coroutine has a separate
    call stack that is preserved across coroutine jumps. It's similar to
    Forth's cooperative multitasking.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sat Apr 4 21:21:25 2026
    From Newsgroup: comp.lang.forth

    Paul Rubin <no.email@nospam.invalid> writes:
    https://doi.org/10.1145/1462166.1462167

    Ehh, that article is very theoretical. I had forgotten what it was
    like, or maybe confused it with a different article. The below is
    probably more readable:

    https://www.lua.org/doc/jucs04.pdf
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Sun Apr 5 23:25:58 2026
    From Newsgroup: comp.lang.forth

    Reposted from the discussion "Euroforth 2025 preliminary proceedings"
    where it had been misposted.

    On 20/01/2026 08:35, Paul Rubin wrote:
    albert@spenarnc.xs4all.nl writes:
    If you pass an address a as a tail call is it approximately equal
    to coroutines:

    No I don't think so. The tail call is just a jump to that address
    (changes the program counter). A coroutine jump also has to change the stack pointer. See the section "Knuth's coroutines" here:

    https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

    Some Forths have a CO primitive that I think is similar. There is
    something like it on the Greenarrays processor.

    Never having looked at coroutines before I tried implementing the
    examples in the above paper. The resulting code is:

    -1 constant EOF

    : get-char ( ca u -- ca' u' [ch | EOF] )
    ?dup 0= if drop EOF exit then
    over c@ >r 1 /string r>
    ;

    : is-alpha ( ch -- f ) 'a' 'z' 1+ within ; \ adequate for testing

    create token 32 chars allot
    2variable tok

    : init-token ( ca u ) token 0 tok 2! ;

    : add-to-token ( ch -- ) tok 2@ + c! 1 tok +! ;

    : got-token ( type -- )
    cr if ." Word: " else ." Punct: " then
    tok 2@ type
    init-token
    ;

    : ?got-token ( ca u ) \ To handle tokens left in the buffer e.g. on EOF
    tok @ if 1 got-token then \ Only needed for WORD tokens
    ;

    \ The consumer
    : parser ( ch -- )
    dup is-alpha
    if
    begin
    add-to-token exit
    [:] parser.alpha ( ch2 ) \ Re-enter here
    dup is-alpha 0=
    until
    then
    ?got-token
    add-to-token
    0 got-token ( Punctuation token )
    exit
    [:] parser.end
    ?got-token
    ;

    \ The producer
    : decompressor ( ca u -- )
    init-token
    begin
    get-char ( -- ca'u' ch ) \ or ( -- EOF )
    dup EOF =
    if drop parser.end cr ." End of file" cr exit then
    dup
    while
    dup $FF =
    if drop get-char >r get-char ( -- ca' u' ch ) ( R: -- len )
    dup parser r> 1
    ?do dup parser.alpha loop
    drop
    else
    parser
    then
    repeat
    ;

    init-token
    s\" \xFF\x03abc%\xFF\x02-&xyz@qwerty" decompressor .s
    \ Displays
    Word: aaabc
    Punct: %
    Punct: -
    Punct: -
    Punct: &
    Word: xyz
    Punct: @
    Word: qwerty
    End of file

    Switching between the routines is achieved by calls to different entry
    points in the Parser, and by EXIT or ; back to the decompressor. This is
    not Standard Forth and uses an extension that I implemented over 10
    years ago, tested but never used. I cannot remember my motivation for
    doing so perhaps somebody mentioned it as an idea. I'd be pleased if
    somebody could point to any previous use of this technique.

    This extension is a word called [:] that behaves like : and can only be
    used in the middle of a standard colon definition. Usage e.g.
    : foo ... [:] bar ... [:] baz ... ;
    to create named entry points into colon definition FOO.
    Such an entry definition compiles no executable code of its own and
    execution of the enclosing definition simply executes the body of the definition as if the alternative entry points weren't there e.g.
    : foo 1 . [:] bar 2 . [:] baz 3 . ;
    foo 1 2 3
    executing the alternative entry points executes the code following
    definition of the entry point e.g.
    bar 2 3
    baz 3
    Using BAR etc in another colon definition calls that entry point just
    like any standard colon definition to run the code following that entry
    point.
    An entry point does not use the control stack in any way, therefore it
    can be positioned inside any control structure.
    An entry point becomes visible immediately its definition is complete,
    so it can be called from anywhere in the rest of the enclosing definition.
    As a pseudo colon definition an entry point has an execution token that
    can be obtained or used by the usual set of words such as ' POSTPONE etc. Execution of code following an entry point can be terminated at any time
    using EXIT

    In the example above in addition to PARSER there are two other entry
    points PARSER.ALPHA (in the middle of a loop) and PARSER.END

    There are other uses for [:] entry points:
    1. Coroutines (see example above)

    2. Recursion by name e.g.
    : foo ... [:] bar ... bar ...; \ recurses to BAR, or
    : foo [foo] ... foo ... ;
    The second example can be achieved by using SYNONYM
    e.g. SYNONYM FOO RECURSE but the first can include initialisation

    3. Obtain the xt of the current definition, which has been requested a
    few times on c.l.f e.g.
    : x [:] my-xt ['] my-xt ... ; \ Removes the need for LATEST

    4. Generators akin to those of Python with next e.g.
    variable n : foo n ! exit [:] foo.next n @ 1 n +! ;
    1 foo
    foo.next ( -- 1 )
    foo.next ( -- 2 )

    5. Debugging by inserting entry points at which a definition can be run
    with known test data on the stack

    6. Nested colon definitions e.g. a possible use - unsure of its utility.
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    b 2 3
    b is effectively a nested colon definition - forbidden by the standard
    --
    Gerry

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Sun Apr 5 23:30:32 2026
    From Newsgroup: comp.lang.forth

    On 05/04/2026 23:25, Gerry Jackson wrote:
    On 05/04/2026 02:02, Paul Rubin wrote:
    Gerry Jackson <do-not-use@swldwa.uk> writes:
    Never having looked at coroutines before I tried implementing the
    examples in the above paper. The resulting code is: ...


    It would take me a while to understand that, but [:] is cool (haven't
    seen it before),

    That's not surprising as I've never posted anything about [:] before.
    That's not to say that it's a new concept it's just that I'm unaware of
    any previous work that is similar.

    and it lets you do something similar to protothreads.

    I've never heard of protothreads let alone used them. Apparently they
    are used extremely lightweight, stackless threads designed for memory-constrained embedded systems. Th+is sounds like they are
    applicable to Forth systems. Do you have any examples of use of
    protothreads.


    For coroutines in general you should also read this:

    https://doi.org/10.1145/1462166.1462167

    It discusses "stackful" coroutines where each coroutine has a separate
    call stack that is preserved across coroutine jumps. It's similar to
    Forth's cooperative multitasking.
    Paul Rubin <no.email@nospam.invalid> writes:
    https://doi.org/10.1145/1462166.1462167

    Ehh, that article is very theoretical. I had forgotten what it was
    like, or maybe confused it with a different article. The below is
    probably more readable:

    https://www.lua.org/doc/jucs04.pdf


    Thanks for the link, very interesting. According to that paper the Forth implementation in my first post is an asymmetric coroutine as are Lua coroutines which they justify in an appendix, stating "it is easy to demonstrate that symmetric coroutines can be expressed by asymmetric facilities"

    According to the paper two fundamental characteristics of a coroutine as follows:
    – “the values of data local to a coroutine persist between successive calls”;
    – “the execution of a coroutine is suspended as control leaves it, only
    to carry on where it left off when control re-enters the coroutine at
    some later stage”

    For the first point, in my example data local to the parser is retained
    but in global variables. That can be made local by putting them in a
    separate wordlist. Using Forth local variables doesn't make sense when
    [:] is used. If it did make sense then local variable values wouldn't be retained.

    For the second point, execution of the parser is certainly suspended but
    it doesn't automatically carry on where it left off when control
    re-enters. The re-entry point has to be called by name. I would think
    that makes it more readable.
    --
    Gerry

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sun Apr 5 17:16:26 2026
    From Newsgroup: comp.lang.forth

    Gerry Jackson <do-not-use@swldwa.uk> writes:
    I've never heard of protothreads let alone used them. Apparently they

    They are basically a fancier version of Simon Tatham's preprocessor
    scheme. In fact I confused the two. See:

    https://dunkels.com/adam/pt/index.html

    Thanks for the link, very interesting. According to that paper the
    Forth implementation in my first post is an asymmetric coroutine as
    are Lua coroutines which they justify in an appendix,

    I think there's a big difference, which is that in Lua, you can call
    something as a coroutine, and it can yield from several levels deep in
    function calls and later resume where it left off. Python originally
    couldn't do that, but it gained the ability later. It's how
    asynchronous i/o works in Python. It also lets you implement
    multitasking, by having the tasks avoid any blocking operations and
    yield frequently to not hog the cpu.

    Forth also often implements something like that, with a cooperative
    multitasker API where you PAUSE every so often, and communicate through mailboxes rather than with return values. It's equivalent though.

    For the first point, in my example data local to the parser is
    retained but in global variables. That can be made local by putting
    them in a separate wordlist. Using Forth local variables doesn't make
    sense when [:] is used. If it did make sense then local variable
    values wouldn't be retained.

    Yes, in the C macro system you use static local variables, somewhatlike
    Forth globals.

    The re-entry point has to be called by name. I would think that makes
    it more readable.

    Does that mean the caller has to know where the coroutine returns from?
    That's more bookkeeping.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Apr 6 13:51:21 2026
    From Newsgroup: comp.lang.forth

    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its utility.
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    b 2 3
    b is effectively a nested colon definition - forbidden by the standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.
    Normal it would be phrased as,
    "A standard Forth is not required to accommodate nested definitions.
    A program relying on such has an environmental dependancy"
    Note that [: .. ;] is in fact nesting definitions. 1]



    In ciforth you can load an extension { } [ ]
    Your example
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    then becomes
    : a 1 . [ : b 2 . 3 . ; ] b drop 4 . ;
    (Maybe with :: ;; that unlinks `b from the dictionary
    to make `b private.}

    Gerry

    1]
    Definition or word, or dictionary entry.
    Definition: a dictionary entry is a logical part of the dictionary that
    bundles the properties of a word/definition.
    Definition: It is identified by a handle, the dea (dictionary entry address) CDFLN SX
    It has a code address: for executing the word, native code.
    It has a data address: contains a pointer to data (buffer, ITC, DTC,)
    It has a flag address: individual bits identify immediate smudged etc.
    It has a link address: that defines a relation its wordlist
    It has a name address: contains a (pointer to) the name
    Extra fields can be added by an implementation.
    Example a source address: points to the source of a word^H^H^H^H d.e..
    Each and all of this fields can be modified without disturbing
    the identity of a dea, e.g.
    "drop" ALLOCATE$ ' DROP >NFA !

    It makes no sense to have a word without a name, old view.
    OTOH a d.e. where the name address contains a null pointer
    makes perfect sense, new view.
    Using dea as an xt :
    EXECUTE ( dea -- ?? ) jump to the address found via the cfa.
    This can be accomplished while the d.e. is not (yet) linked
    into a wordlist, or floating in ALLOCATEd space, or temporary
    in a spare dictionary area that is about to be destroyed,
    or even if the "word" has no name.

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Mon Apr 6 19:58:08 2026
    From Newsgroup: comp.lang.forth

    On 06/04/2026 01:16, Paul Rubin wrote:
    Gerry Jackson <do-not-use@swldwa.uk> writes:
    I've never heard of protothreads let alone used them. Apparently they

    They are basically a fancier version of Simon Tatham's preprocessor
    scheme. In fact I confused the two. See:

    https://dunkels.com/adam/pt/index.html

    Thanks for the link, very interesting. According to that paper the
    Forth implementation in my first post is an asymmetric coroutine as
    are Lua coroutines which they justify in an appendix,

    I think there's a big difference, which is that in Lua, you can call something as a coroutine, and it can yield from several levels deep in function calls and later resume where it left off.

    I presume that means that the coroutine yielding has to have its own
    return and data stacks which I've not considered. If that's the case
    then an alternative to call by name suggested below should be able to
    handle that case.

    Python originally
    couldn't do that, but it gained the ability later. It's how
    asynchronous i/o works in Python. It also lets you implement
    multitasking, by having the tasks avoid any blocking operations and
    yield frequently to not hog the cpu.

    Forth also often implements something like that, with a cooperative multitasker API where you PAUSE every so often, and communicate through mailboxes rather than with return values. It's equivalent though.

    ...

    The re-entry point has to be called by name. I would think that makes
    it more readable.

    Does that mean the caller has to know where the coroutine returns from? That's more bookkeeping.

    Yes and that's presumably undesirable for multi-tasking. A solution to
    that could use the fact that the [:] entry point has an xt that can be
    stored as data prior to returning (yielding). The best way would be to
    have a variant of [:] that saved the xt of the re-entry point in a
    deferred word. On re-entry the saved xt would be executed to take
    control to the correct place. An alternative would be to pass the
    re-entry back to the caller so the it could execute the xt. But that has
    the disadvantage that the xt has to be remembered by the caller.
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Mon Apr 6 22:20:05 2026
    From Newsgroup: comp.lang.forth

    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its utility.
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    b 2 3
    b is effectively a nested colon definition - forbidden by the standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition
    were ambiguous or had an environmental dependency and I couldn't find anything. I always assumed it wasn't permited - perhaps it is.

    Normal it would be phrased as,
    "A standard Forth is not required to accommodate nested definitions.
    A program relying on such has an environmental dependancy"
    Note that [: .. ;] is in fact nesting definitions. 1]

    In ciforth you can load an extension { } [ ]
    Your example
    : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    then becomes
    : a 1 . [ : b 2 . 3 . ; ] b drop 4 . ;

    That's interesting but I didn't have the call to b and the drop was
    simply to drop the xt of the quotation.

    My system can handle nested definitions e.g.
    : a 1 . [ : b 2 . 3 . ; ] 4 . ;
    a 1 4 ok
    b 2 3 ok

    It aso handles other types of definitions inside a colon definition i.e. variables etc.



    1]
    Definition or word, or dictionary entry.
    Definition: a dictionary entry is a logical part of the dictionary that bundles the properties of a word/definition.
    Definition: It is identified by a handle, the dea (dictionary entry address) CDFLN SX
    It has a code address: for executing the word, native code.
    It has a data address: contains a pointer to data (buffer, ITC, DTC,)
    It has a flag address: individual bits identify immediate smudged etc.
    It has a link address: that defines a relation its wordlist
    It has a name address: contains a (pointer to) the name
    Extra fields can be added by an implementation.
    Example a source address: points to the source of a word^H^H^H^H d.e..
    Each and all of this fields can be modified without disturbing
    the identity of a dea, e.g.
    "drop" ALLOCATE$ ' DROP >NFA !

    It makes no sense to have a word without a name, old view.
    OTOH a d.e. where the name address contains a null pointer
    makes perfect sense, new view.
    Using dea as an xt :
    EXECUTE ( dea -- ?? ) jump to the address found via the cfa.
    This can be accomplished while the d.e. is not (yet) linked
    into a wordlist, or floating in ALLOCATEd space, or temporary
    in a spare dictionary area that is about to be destroyed,
    or even if the "word" has no name.

    Groetjes Albert
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Apr 7 13:23:49 2026
    From Newsgroup: comp.lang.forth

    In article <874ilpaqp1.fsf@nightsong.com>,
    Paul Rubin <no.email@nospam.invalid> wrote:
    I think there's a big difference, which is that in Lua, you can call >something as a coroutine, and it can yield from several levels deep in >function calls and later resume where it left off. Python originally >couldn't do that, but it gained the ability later. It's how
    asynchronous i/o works in Python. It also lets you implement
    multitasking, by having the tasks avoid any blocking operations and
    yield frequently to not hog the cpu.

    I have 100+ cores concurrently. I don't want to yield anything.


    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Apr 7 13:35:25 2026
    From Newsgroup: comp.lang.forth

    In article <10r1825$2d8j6$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its utility. >>> : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
    b 2 3
    b is effectively a nested colon definition - forbidden by the standard >>
    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition
    were ambiguous or had an environmental dependency and I couldn't find >anything. I always assumed it wasn't permited - perhaps it is.

    You have been bamboozled nu the wording.
    No one can forbid an implementation to add a facility like this. The
    wording is such to scare implementors like me. Note that this doesn't
    interfere at all with compliance to the standard. If it is common
    place to add nested compilation they have to add this sooner or later.
    The prize is a non-standard program. Point me to a program that
    does something useful, and doesn't contain implementation dependant
    parts.
    Now it is a good time to recapitulate my postings
    "The four brackets of the apocalypse."

    A good test of whether an architecture is sound, is whether
    fullfilling such request is easy.
    I'm proud that in all programs I designed,reasonable extension were
    easy.

    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    <SNIP>
    --
    Gerry

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Apr 7 09:28:02 2026
    From Newsgroup: comp.lang.forth

    On 4/6/26 4:20 PM, Gerry Jackson wrote:
    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its utility. >>>     : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
        b 2 3
        b is effectively a nested colon definition - forbidden by the
    standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition
    were ambiguous or had an environmental dependency and I couldn't find anything. I always assumed it wasn't permited - perhaps it is.


    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for
    certain architectures.

    --
    Krishna

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Tue Apr 7 16:12:51 2026
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >shall not execute any defining word, :NONAME, or any definition that >allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >certain architectures.

    I think it was existing practice: Most systems did not support nested definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    - 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: https://forth-standard.org/
    EuroForth 2025 proceedings: http://www.euroforth.org/ef25/papers/
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Tue Apr 7 20:55:37 2026
    From Newsgroup: comp.lang.forth

    On 07/04/2026 12:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    On the contrary, Ruvim posted some code that is a standard program and
    which distinguises between a parsing TO and one that sets a flag for a following VALUE to act on.

    I can't find the post but the gist of it was (I think):

    1 value v1
    2 value v2 immediate
    : test to v2 v1 ;
    Running test with
    3 test
    A parsing TO will set v2 to 3
    A flagging TO will execute v2 during compilation of test because it is immediate. So test will set v1 to 3 leaving v2 unchanged.
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Apr 7 18:06:08 2026
    From Newsgroup: comp.lang.forth

    On 4/7/26 11:12 AM, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    ...

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for
    certain architectures.

    I think it was existing practice: Most systems did not support nested definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.


    kForth supports :NONAME definitions when the current definition is
    suspended. It is the means by which quotations are defined.

    : [: postpone [ :noname ; immediate

    : ;] postpone ; ] postpone literal ; immediate

    It does not support named definitions (definitions which allocate
    dictionary space) during suspended compilation of a definition.

    --
    Krishna

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 11:33:25 2026
    From Newsgroup: comp.lang.forth

    On 07/04/2026 15:28, Krishna Myneni wrote:
    On 4/6/26 4:20 PM, Gerry Jackson wrote:
    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its
    utility.
        : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
        b 2 3
        b is effectively a nested colon definition - forbidden by the
    standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition
    were ambiguous or had an environmental dependency and I couldn't find
    anything. I always assumed it wasn't permited - perhaps it is.


    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program shall not execute any defining word, :NONAME, or any definition that allocates dictionary data space.

    Thanks I missed that. Those statements would seem to rule out quotations except that it could be argued that the definition of [: and ;] does not suspend compilation - its part of the enclosing colon definition.
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Wed Apr 8 12:34:17 2026
    From Newsgroup: comp.lang.forth

    In article <10r3nfo$33464$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 12:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    On the contrary, Ruvim posted some code that is a standard program and
    which distinguises between a parsing TO and one that sets a flag for a >following VALUE to act on.

    I can't find the post but the gist of it was (I think):

    1 value v1
    2 value v2 immediate
    : test to v2 v1 ;
    Running test with
    3 test
    A parsing TO will set v2 to 3
    A flagging TO will execute v2 during compilation of test because it is >immediate. So test will set v1 to 3 leaving v2 unchanged.

    No it doesn't. It leaves garbage on the stack during compilation,
    leading to mostly an error.
    I leave it up to the reader whether this counts as a standard program.

    I overlooked this clever example.
    So I guess my VALUE is non compliant, proven by a contrived test.

    It still makes no sense to forbid a flagging implementation.
    (Also VALUE's don't make sense, anyway.)


    --
    Gerry

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 11:43:37 2026
    From Newsgroup: comp.lang.forth

    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for
    certain architectures.
    I think it was existing practice: Most systems did not support nested definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work
    --
    Gerry

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Wed Apr 8 13:07:04 2026
    From Newsgroup: comp.lang.forth

    In article <10r5atl$3g8d5$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 15:28, Krishna Myneni wrote:
    On 4/6/26 4:20 PM, Gerry Jackson wrote:
    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its
    utility.
        : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
        b 2 3
        b is effectively a nested colon definition - forbidden by the >>>>> standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition
    were ambiguous or had an environmental dependency and I couldn't find
    anything. I always assumed it wasn't permited - perhaps it is.


    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.

    Thanks I missed that. Those statements would seem to rule out quotations >except that it could be argued that the definition of [: and ;] does not >suspend compilation - its part of the enclosing colon definition.

    "part of the" a really Jezuitic argument.

    It also forbids
    : there 3 ;
    : test .. [ ' three COMPILE, ] ... ;
    a technique that should be kosher.

    It is more proof that the term "forbid" has no place in the wording of the restriction. An implementor of [: has options he sees fit, including
    - skipping over an area, that is unused by the current definition,
    - temperarily compiling to an alternative HERE, transporting back later
    to the regular HERE. ( FAR-DP SWAP-DP TRIM approach use for my OO).
    After the current definition finishes copy bake to a new HERE.
    - using ALLOCATEd space, or
    - invoking a c-compiler.

    [: ;] renamed { } to ( include :NONAME ) is readily implemented
    by the four nestings of the apocalypse:

    : { (( (s ({) ; IMMEDIATE
    : } >R (}) s) )) R> 'LITERAL EXECUTE ; IMMEDIATE

    With a refurbished [ ] it implements unconstrained nesting :

    : doit .. [ .. { ..} .. { .. [ .. ] .. } .. ] .. ;

    (The four brackets comprise one screen. Only words
    from the ciforth kernel needed. So in a proper architecture
    it is straightforward. )

    --
    Gerry

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Wed Apr 8 13:16:41 2026
    From Newsgroup: comp.lang.forth

    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for
    certain architectures.
    I think it was existing practice: Most systems did not support nested
    definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;
    OK
    3 4 hyp*2 .
    25 OK

    ( This is the infamous Pythogarean triangle. )

    --
    Gerry

    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 12:32:56 2026
    From Newsgroup: comp.lang.forth

    On 08/04/2026 11:34, albert@spenarnc.xs4all.nl wrote:
    In article <10r3nfo$33464$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 12:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    On the contrary, Ruvim posted some code that is a standard program and
    which distinguises between a parsing TO and one that sets a flag for a
    following VALUE to act on.

    I can't find the post but the gist of it was (I think):

    1 value v1
    2 value v2 immediate
    : test to v2 v1 ;
    Running test with
    3 test
    A parsing TO will set v2 to 3
    A flagging TO will execute v2 during compilation of test because it is
    immediate. So test will set v1 to 3 leaving v2 unchanged.

    No it doesn't. It leaves garbage on the stack during compilation,
    leading to mostly an error.

    Do you mean your system does that?

    My mistake, I should have written:
    A flagging TO should ...

    I leave it up to the reader whether this counts as a standard program.

    Contrived test or not it is standard.

    I overlooked this clever example.
    As did everybody else until Ruvim devised it.

    So I guess my VALUE is non compliant, proven by a contrived test.

    Yes


    It still makes no sense to forbid a flagging implementation.

    I have some sympathy with that but it does ensure that TO has to be on
    the same line as the value name and that the value name does occur
    immediately after the TO as there can be multiple TOs in succession or
    other intervening code (provided TO doesn't leave garbage on the stack).
    Anyway surely a flagging TO is slower as it has to test the flag?

    (Also VALUE's don't make sense, anyway.)

    VALUEs make more sense than some other things in the standard!
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Wed Apr 8 14:22:50 2026
    From Newsgroup: comp.lang.forth

    On 07-04-2026 18:12, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for
    certain architectures.

    I think it was existing practice: Most systems did not support nested definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    - anton

    In 4tH, these are completely equivalent:

    : Hello [: ." Hello world" cr ;] execute ;
    : Hello :NONAME ." Hello world" cr ; execute ;

    Yes, Forth has "references" in order to match IF..THEN thingies. It
    works as well for : and ;.

    You can even define:

    : Hello : World ." Hello world" cr ; ;

    .. for that reason, but since it doesn't leave an address, it only works
    if you do "world".

    In short, this program:

    : Hello1 [: ." Hello world" cr ;] execute ;
    : Hello2 :NONAME ." Hello world" cr ; execute ;
    : Hello3 : World ." Hello world" cr ; ;

    Hello1 Hello2 Hello3 World

    .. renders:

    ---8<---
    Hello world
    Hello world
    Hello world
    ---8<---

    Hans Bezemer

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Apr 8 11:47:16 2026
    From Newsgroup: comp.lang.forth

    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >>>> shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>> certain architectures.
    I think it was existing practice: Most systems did not support nested
    definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;
    OK
    3 4 hyp*2 .
    25 OK
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25 ok

    Incidentally, is the scope of your definition of SQ limited to the
    definition of hyp*2 in your example above? Or is SQ added to the
    dictionary like a regular definition?

    --
    Krishna




    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 21:26:43 2026
    From Newsgroup: comp.lang.forth

    On 08/04/2026 12:16, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >>>> shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>> certain architectures.
    I think it was existing practice: Most systems did not support nested
    definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    Guilty.


    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;

    That's the natural syntax to use, why invent another?

    OK
    3 4 hyp*2 .
    25 OK

    That also worked on my system


    ( This is the infamous Pythogarean triangle. )
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 21:48:12 2026
    From Newsgroup: comp.lang.forth

    On 08/04/2026 17:47, Krishna Myneni wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a
    program
    shall not execute any defining word, :NONAME, or any definition that >>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>>> certain architectures.
    I think it was existing practice: Most systems did not support nested
    definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo  ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
      OK
       : hyp*2 [ : SQ DUP * ; ]  SQ SWAP SQ + ;
        OK
        3 4 hyp*2 .
        25  OK
    ...

    I assume you can also compile :NONAME definitions while the current definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25  ok

    Works on my system. Both HYP^2 and SQ are added to the current wordlist.


    Incidentally, is the scope of your definition of SQ limited to the definition of hyp*2 in your example above? Or is SQ added to the
    dictionary like a regular definition?


    I think I implemented nesting ( at the same time as [:] ) to make
    definition of modules easy. e.g. a module definition would call : and
    set public and private wowrdlists. So all defining words can be nested
    inside a colon defintion. But I never got round to using nested definitions.
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Apr 8 22:05:26 2026
    From Newsgroup: comp.lang.forth

    On 08/04/2026 12:07, albert@spenarnc.xs4all.nl wrote:
    In article <10r5atl$3g8d5$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 15:28, Krishna Myneni wrote:
    On 4/6/26 4:20 PM, Gerry Jackson wrote:
    On 06/04/2026 12:51, albert@spenarnc.xs4all.nl wrote:
    In article <10qunhm$1nnbt$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    <SNIP>
    6. Nested colon definitions e.g. a possible use - unsure of its
    utility.
        : a 1 . [: [:] b 2 . 3 . ;] drop 4 . ;
        b 2 3
        b is effectively a nested colon definition - forbidden by the >>>>>> standard

    The term forbidden sneaks in probably by implementors that have
    absolutely no intention to implement this.

    Hmm I just scanned the Forth 2012 document to see if nested definition >>>> were ambiguous or had an environmental dependency and I couldn't find
    anything. I always assumed it wasn't permited - perhaps it is.


    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program
    shall not execute any defining word, :NONAME, or any definition that
    allocates dictionary data space.

    Thanks I missed that. Those statements would seem to rule out quotations
    except that it could be argued that the definition of [: and ;] does not
    suspend compilation - its part of the enclosing colon definition.

    "part of the" a really Jezuitic argument.

    Oh, I had to look up what that meant.


    It also forbids
    : there 3 ;
    : test .. [ ' three COMPILE, ] ... ;

    So it would seem.

    a technique that should be kosher.

    I agree that should be ok (except that COMPILE, has undefined
    interpretation semantics).

    It is more proof that the term "forbid" has no place in the wording of the restriction. An implementor of [: has options he sees fit, including
    - skipping over an area, that is unused by the current definition,
    - temperarily compiling to an alternative HERE, transporting back later
    to the regular HERE. ( FAR-DP SWAP-DP TRIM approach use for my OO).
    After the current definition finishes copy bake to a new HERE.
    - using ALLOCATEd space, or
    - invoking a c-compiler.

    [: ;] renamed { } to ( include :NONAME ) is readily implemented
    by the four nestings of the apocalypse:

    : { (( (s ({) ; IMMEDIATE
    : } >R (}) s) )) R> 'LITERAL EXECUTE ; IMMEDIATE

    With a refurbished [ ] it implements unconstrained nesting :

    : doit .. [ .. { ..} .. { .. [ .. ] .. } .. ] .. ;

    (The four brackets comprise one screen. Only words
    from the ciforth kernel needed. So in a proper architecture
    it is straightforward. )

    My system has unconstrained nesting but it doesn't need any change to [
    and ] - I'd be hard pressed to justify nesting more than one level.
    --
    Gerry
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Stephen Pelc@stephen@vfxforth.com to comp.lang.forth on Thu Apr 9 10:12:42 2026
    From Newsgroup: comp.lang.forth

    On 7 Apr 2026 at 21:55:37 CEST, "Gerry Jackson" <do-not-use@swldwa.uk> wrote:

    On 07/04/2026 12:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    On the contrary, Ruvim posted some code that is a standard program and
    which distinguises between a parsing TO and one that sets a flag for a following VALUE to act on.

    VFX sets a flag for TO and friends and has done so for 30+ years. We have no intention of changing despite the cleverness of Ruvim's detection scheme. We take the "as if" position because
    a) it simplifies implementation.
    b) no user has complained.

    Stephen
    --
    Stephen Pelc, stephen@vfxforth.com
    Wodni & Pelc GmbH
    Vienna, Austria
    Tel: +44 (0)7803 903612, +34 649 662 974 http://www.vfxforth.com/downloads/VfxCommunity/
    free VFX Forth downloads
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Apr 9 13:01:05 2026
    From Newsgroup: comp.lang.forth

    In article <10r60qk$3nqft$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >>>>> shall not execute any defining word, :NONAME, or any definition that >>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>>> certain architectures.
    I think it was existing practice: Most systems did not support nested
    definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do,
    the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;
    OK
    3 4 hyp*2 .
    25 OK
    ...

    I assume you can also compile :NONAME definitions while the current >definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25 ok

    Actually you can't. After -nesting- the brackets use the data stack extensively.
    You enter an isolated world between [ and ] .
    Your example could become
    "
    WANT -nesting- CASE-INSENSITIVE :NONAME

    : hyp^2 [ :NONAME dup * ; CONSTANT NONAME ] NONAME dup >r execute swap r> execute + ;
    "
    Normally you would do

    : hyp^2 { dup * } dup >r execute swap r> execute + ;

    Incidentally, is the scope of your definition of SQ limited to the
    definition of hyp*2 in your example above? Or is SQ added to the
    dictionary like a regular definition?

    It is added like a regular definition, however.
    I have experimented with :: ;; in place of : and ;
    The ;; removes inside definitions.
    I am not in the habit of proposing

    This is all well and cute, but in actual use is only
    { and } as a simple a replacement for both
    :NONAME and [: ;] .

    What this does for simplification can be seen by the
    following altenatives for adding an xt to a set of
    real time task:

    ===========================
    \ Regular Forth code:
    100 1 EVENT-BUFFER SILVER-QUEUE

    \ Activate or deactivate the hammer of EVENT.
    : TOGGLE-NOTE-SILVER SILVER-DATA SILVER-INTERFACE ADVANCE-NOTE ;

    \ The real time action of the silver tingle.
    : RT-SILVER SILVER-QUEUE ['] TOGGLE-NOTE-SILVER TRY ;

    ' RT-SILVER REALTIME-TASKS SET+

    =========================================
    \ First step.

    100 1 EVENT-BUFFER SILVER-QUEUE

    \ The quotation is activate or deactivate the hammer of EVENT.

    \ The real time action of the silver tingle.
    : RT-SILVER SILVER-QUEUE { SILVER-DATA SILVER-INTERFACE ADVANCE-NOTE } TRY ;

    ' RT-SILVER REALTIME-TASKS SET+

    ====================================
    \ Final

    100 1 EVENT-BUFFER SILVER-QUEUE

    \ The quotation is activate or deactivate the hammer of EVENT.

    \ The real time action of the silver tingle. Now use { } as :NONAME .
    { SILVER-QUEUE { SILVER-DATA SILVER-INTERFACE ADVANCE-NOTE } TRY } REALTIME-TASKS SET+

    ========================
    \ Using ISO anonymous behaviour.:
    100 1 EVENT-BUFFER SILVER-QUEUE

    \ The real time action of the silver tingle.
    :NONAME SILVER-QUEUE [: SILVER-DATA SILVER-INTERFACE ADVANCE-NOTE ;] TRY ;
    REALTIME-TASKS SET+
    =========================================

    The latter example illustrates how adhoc :NONAME and [: actually are.
    Note how the ' and ['] are eliminated even in the ISO case.

    --
    Krishna
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Apr 9 07:01:13 2026
    From Newsgroup: comp.lang.forth

    On 4/9/26 6:01 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r60qk$3nqft$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >>>>>> shall not execute any defining word, :NONAME, or any definition that >>>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>>>> certain architectures.
    I think it was existing practice: Most systems did not support nested >>>>> definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do, >>>>> the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;
    OK
    3 4 hyp*2 .
    25 OK
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25 ok

    Actually you can't. After -nesting- the brackets use the data stack extensively.
    You enter an isolated world between [ and ] .
    Your example could become
    "
    WANT -nesting- CASE-INSENSITIVE :NONAME

    : hyp^2 [ :NONAME dup * ; CONSTANT NONAME ] NONAME dup >r execute swap r> execute + ;
    "

    So you can never use "[ ... ] LITERAL" when nesting is in effect in
    ciforth?

    --
    Krishna


    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Apr 9 07:06:19 2026
    From Newsgroup: comp.lang.forth

    On 4/8/26 3:48 PM, Gerry Jackson wrote:
    On 08/04/2026 17:47, Krishna Myneni wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be
    suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a
    program
    shall not execute any defining word, :NONAME, or any definition that >>>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do >>>>>> for
    certain architectures.
    I think it was existing practice: Most systems did not support nested >>>>> definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do, >>>>> the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo  ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
      OK
       : hyp*2 [ : SQ DUP * ; ]  SQ SWAP SQ + ;
        OK
        3 4 hyp*2 .
        25  OK
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25  ok

    Works on my system. Both HYP^2 and SQ are added to the current wordlist.
    ...

    Thanks, Gerry. I was going to suggest that maybe we can propose to get
    the reference to :NONAME removed from the Forth 20xx standard statement
    in 3.4.5 Compilation,

    "While the compilation of the current definition is suspended, a
    program shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    There may not be enough common practice, though.

    --
    Krishna



    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Apr 9 16:10:21 2026
    From Newsgroup: comp.lang.forth

    In article <10r84e9$9tt0$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/9/26 6:01 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r60qk$3nqft$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be suspended >>>>>>> using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a program >>>>>>> shall not execute any defining word, :NONAME, or any definition that >>>>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do for >>>>>>> certain architectures.
    I think it was existing practice: Most systems did not support nested >>>>>> definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do, >>>>>> the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
    OK
    : hyp*2 [ : SQ DUP * ; ] SQ SWAP SQ + ;
    OK
    3 4 hyp*2 .
    25 OK
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25 ok

    Actually you can't. After -nesting- the brackets use the data stack extensively.
    You enter an isolated world between [ and ] .
    Your example could become
    "
    WANT -nesting- CASE-INSENSITIVE :NONAME

    : hyp^2 [ :NONAME dup * ; CONSTANT NONAME ] NONAME dup >r execute swap r> execute + ;
    "

    So you can never use "[ ... ] LITERAL" when nesting is in effect in
    ciforth?
    No, but you don't use nesting normally.
    I use extra facilities parsimonily.
    I never do those LITERAL trick anyway.

    --
    Krishna

    Groetjes Albert

    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Apr 9 16:41:27 2026
    From Newsgroup: comp.lang.forth

    In article <10r84nr$9tt0$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/8/26 3:48 PM, Gerry Jackson wrote:
    On 08/04/2026 17:47, Krishna Myneni wrote:
    On 4/8/26 6:16 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r5bgp$3gdvd$1@dont-email.me>,
    Gerry Jackson  <do-not-use@swldwa.uk> wrote:
    On 07/04/2026 17:12, Anton Ertl wrote:
    Krishna Myneni<krishna.myneni@ccreweb.org> writes:
    It is in section 3.4.5, in particular the 2nd paragraph:

    3.4.5
    Compilation
    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. The compilation of the current definition may be
    suspended
    using [ (left-bracket) and resumed using ] (right-bracket).

    While the compilation of the current definition is suspended, a
    program
    shall not execute any defining word, :NONAME, or any definition that >>>>>>> allocates dictionary data space.


    It seems entirely frivolous to me, but maybe it is difficult to do >>>>>>> for
    certain architectures.
    I think it was existing practice: Most systems did not support nested >>>>>> definitions when Forth-94 was standardized, and I guess that most
    systems do not support general nesting to this day, and when they do, >>>>>> the syntax is system-dependent.

    I agree except that a few systems I tried compiled existing syntax
    e.g.

    : foo  ... [ : bar ... ; ] ... ;

    but the results didn't work

    You didn't try ciforth.

    ~/PROJECT/ciforths/ciforth: lina -a
    WANT -nesting-
    [ : ISN'T UNIQUE
    ] : ISN'T UNIQUE
    -nesting- : (WARNING) NOT PRESENT, THOUGH WANTED
      OK
       : hyp*2 [ : SQ DUP * ; ]  SQ SWAP SQ + ;
        OK
        3 4 hyp*2 .
        25  OK
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ;
    ok
    3 4 hyp^2 .
    25  ok

    Works on my system. Both HYP^2 and SQ are added to the current wordlist.
    ...

    Thanks, Gerry. I was going to suggest that maybe we can propose to get
    the reference to :NONAME removed from the Forth 20xx standard statement
    in 3.4.5 Compilation,

    "While the compilation of the current definition is suspended, a
    program shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    There may not be enough common practice, though.

    I propose a different view. A denotation can occupy (dictionary) space, e.g.
    a string.
    "AAPESTRING" reserves space, and leaves a pointer to the data structure.
    Like wise
    { DUP * } defines a behaviour and leaves a pointer. There is actually
    not much difference.
    In a lispy implementation both can be ALLOCATEd instead of ALLOTed, but
    that is neither here nor there.
    (OTOH 0x89080 leaves only a stack item, needs no allocation).
    This encompasses a lot of what recognizers accomplishes at a low
    conceptual price.
    E.g. to implement strings like "ORANG UTAN" :
    : (( 'AHEAD COMPILE, (FORWARD ; : )) FORWARD) ; \ On of the brackets
    Now a string prefix " does approximately
    (( &" PARSE ROT )) DLITERAL

    Also something like this could work:
    AHEAD { '"' PARSE ROT ] THEN DLITERAL

    Doing { } in interpretation state wastes a couple of bytes. ;-)

    UNUSED .
    16844131800 OK


    --
    Krishna

    Groetjes Albert
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Apr 9 13:29:54 2026
    From Newsgroup: comp.lang.forth

    On 4/9/26 9:10 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r84e9$9tt0$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    ...

    I assume you can also compile :NONAME definitions while the current
    definition is suspended in ciforth e.g.

    : hyp^2 [ :NONAME dup * ; ] literal dup >r execute swap r> execute + ; >>>> ok
    3 4 hyp^2 .
    25 ok

    Actually you can't. After -nesting- the brackets use the data stack extensively.
    You enter an isolated world between [ and ] .
    Your example could become
    "
    WANT -nesting- CASE-INSENSITIVE :NONAME

    : hyp^2 [ :NONAME dup * ; CONSTANT NONAME ] NONAME dup >r execute swap r> execute + ;
    "

    So you can never use "[ ... ] LITERAL" when nesting is in effect in
    ciforth?
    No, but you don't use nesting normally.
    I use extra facilities parsimonily.
    I never do those LITERAL trick anyway.

    The sequence "[ ... ] LITERAL" is a Forth staple for computing a
    quantity during a suspended definition and compiling the result in the
    resumed definition. It appears quite a bit in my code.

    --
    Krishna

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Apr 9 13:34:54 2026
    From Newsgroup: comp.lang.forth

    On 4/9/26 9:41 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r84nr$9tt0$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    ....

    "While the compilation of the current definition is suspended, a
    program shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    There may not be enough common practice, though.

    I propose a different view. A denotation can occupy (dictionary) space, e.g. a string.
    "AAPESTRING" reserves space, and leaves a pointer to the data structure.
    Like wise
    { DUP * } defines a behaviour and leaves a pointer. There is actually
    not much difference.

    The notation " ... }" conflicts directly with the Forth Scientific
    Library notation for arrays of different types, unless "}" is simply a delimiter for a parsing word. In your usage, I don't think "{" is a
    parsing word.

    I remember pointing this out when "{ ... }" was proposed for a newer
    version of locals and the notation was changed.

    --
    Krishna

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Apr 10 01:23:59 2026
    From Newsgroup: comp.lang.forth

    In article <10r8rgf$i0s4$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/9/26 9:41 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r84nr$9tt0$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    ....

    "While the compilation of the current definition is suspended, a
    program shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    There may not be enough common practice, though.

    I propose a different view. A denotation can occupy (dictionary) space, e.g. >> a string.
    "AAPESTRING" reserves space, and leaves a pointer to the data structure.
    Like wise
    { DUP * } defines a behaviour and leaves a pointer. There is actually
    not much difference.

    The notation " ... }" conflicts directly with the Forth Scientific
    Library notation for arrays of different types, unless "}" is simply a >delimiter for a parsing word. In your usage, I don't think "{" is a
    parsing word.

    I remember pointing this out when "{ ... }" was proposed for a newer
    version of locals and the notation was changed.

    We run out of brackets. Maybe abandon ( ) for comments, and use only \ .
    Then ( ) is freed for math formulaes.

    --
    Krishna

    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Apr 9 21:34:26 2026
    From Newsgroup: comp.lang.forth

    On 4/9/26 6:23 PM, albert@spenarnc.xs4all.nl wrote:
    In article <10r8rgf$i0s4$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    On 4/9/26 9:41 AM, albert@spenarnc.xs4all.nl wrote:
    In article <10r84nr$9tt0$2@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    ....

    "While the compilation of the current definition is suspended, a
    program shall not execute any defining word, :NONAME, or any definition >>>> that allocates dictionary data space."

    There may not be enough common practice, though.

    I propose a different view. A denotation can occupy (dictionary) space, e.g.
    a string.
    "AAPESTRING" reserves space, and leaves a pointer to the data structure. >>> Like wise
    { DUP * } defines a behaviour and leaves a pointer. There is actually
    not much difference.

    The notation " ... }" conflicts directly with the Forth Scientific
    Library notation for arrays of different types, unless "}" is simply a
    delimiter for a parsing word. In your usage, I don't think "{" is a
    parsing word.

    I remember pointing this out when "{ ... }" was proposed for a newer
    version of locals and the notation was changed.

    We run out of brackets. Maybe abandon ( ) for comments, and use only \ .
    Then ( ) is freed for math formulaes.


    Your idea of using "::" and just extending ";" to handle the nested
    named definition (in similar fashion as using ";" with :NONAME) is
    workable. Having a ":" in the compilation word would retain consistency.

    --
    KM

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Apr 10 19:01:36 2026
    From Newsgroup: comp.lang.forth

    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of.
    Why, you ask? Because every name basically returns a pointer - unless we
    DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word? Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or
    assignment is. Is the address known at compile time, we handle it like a VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design.

    Hans Bezemer

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Apr 11 11:54:46 2026
    From Newsgroup: comp.lang.forth

    On 11/04/2026 3:01 am, Hans Bezemer wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of. Why, you ask? Because every name basically returns a pointer - unless we DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word? Really? And all of a sudden it should do different things depending on type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler figures out what the most optimal way of handling this retrieval or assignment is. Is the address known at compile time, we handle it like a VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some smart@$$ "TO" even less. What a waste of code.. And what a horrible design.

    It's an old problem - something that ought not be required, yet appears to
    fill a need. In addition to VALUE, I have INTEGER (aka 0 VALUE). Thus far I've not tired of it. Sometimes I could use 2VALUE in an app but have
    resisted the urge. The occasions are simply too few to warrant. I provide definitions for 2VALUE 2TO FVALUE FTO should a user really, really, want them.

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From peter@peter.noreply@tin.it to comp.lang.forth on Sat Apr 11 09:49:20 2026
    From Newsgroup: comp.lang.forth

    On Fri, 10 Apr 2026 19:01:36 +0200
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:

    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of. Why, you ask? Because every name basically returns a pointer - unless we DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word? Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or assignment is. Is the address known at compile time, we handle it like a VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design.

    Hans Bezemer


    I agree to this! I stopped using VALUES over 10 years ago when
    TO got overloaded. I have not missed them.

    In my system the code produced is exactly the same anyway!

    BR
    Peter

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sat Apr 11 22:03:32 2026
    From Newsgroup: comp.lang.forth

    In article <nnd$5fbdae9b$6428335d@7ddbf5ece7eb9625>,
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of.
    Why, you ask? Because every name basically returns a pointer - unless we >DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word? >Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or >assignment is. Is the address known at compile time, we handle it like a >VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design.

    In ciforth you can do this:
    Prefixes ("recognizers") are supposed to be parsing the remainder
    lf tne word, like $DEADBEAT

    Abuse follows.

    \ In the minimal wordlist, not masking regular @ !
    'ONLY >WID CURRENT !
    : @ NAME EVALUATE @ ; PREFIX IMMEDIATE
    : ! NAME EVALUATE ! ; PREFIX IMMEDIATE
    DEFINITINS \ Snap back.

    VARIABLE AAP
    12 !AAP
    @AAP .
    12 OK
    13 !AAP
    @AAP .
    13 OK

    Just saying.

    (I don't recommend this, by the way.)



    Hans Bezemer

    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Apr 12 12:49:59 2026
    From Newsgroup: comp.lang.forth

    On 12/04/2026 6:03 am, albert@spenarnc.xs4all.nl wrote:
    In article <nnd$5fbdae9b$6428335d@7ddbf5ece7eb9625>,
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of.
    Why, you ask? Because every name basically returns a pointer - unless we
    DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word?
    Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or
    assignment is. Is the address known at compile time, we handle it like a
    VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design.

    In ciforth you can do this:
    Prefixes ("recognizers") are supposed to be parsing the remainder
    lf tne word, like $DEADBEAT

    Abuse follows.

    \ In the minimal wordlist, not masking regular @ !
    'ONLY >WID CURRENT !
    : @ NAME EVALUATE @ ; PREFIX IMMEDIATE
    : ! NAME EVALUATE ! ; PREFIX IMMEDIATE
    DEFINITINS \ Snap back.

    VARIABLE AAP
    12 !AAP
    @AAP .
    12 OK
    13 !AAP
    @AAP .
    13 OK

    Just saying.

    (I don't recommend this, by the way.)

    AFAICT the majority of HLL's use 'self-fetching' variables. Setting a
    variable required something like := which corresponds to forth's TO.
    IMO local variables in forth was less about 'stack juggling' than
    simulating the 'look and feel' code of other languages. Forth locals
    code uses a fair number of TO's. Hugh once suggested locals ought to
    have used @ ! . This would have been very forth-like - but completely
    misses what locals aficionados were trying to do!

    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets
    used. Without that distinction I'd find it hard justifying VALUEs - or
    indeed know when to use them. By clearly stating their intent and usage,
    they provide semantic value to written code and the language in general.
    But I'm not sure ANS ever did say - leaving users to muddle it out for themselves. Locals' use of 'values' and TO only muddied the waters.



    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Apr 12 12:13:27 2026
    From Newsgroup: comp.lang.forth

    In article <69db0856$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2026 6:03 am, albert@spenarnc.xs4all.nl wrote:
    In article <nnd$5fbdae9b$6428335d@7ddbf5ece7eb9625>,
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of. >>> Why, you ask? Because every name basically returns a pointer - unless we >>> DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word?
    Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or
    assignment is. Is the address known at compile time, we handle it like a >>> VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design. >>
    In ciforth you can do this:
    Prefixes ("recognizers") are supposed to be parsing the remainder
    lf tne word, like $DEADBEAT

    Abuse follows.

    \ In the minimal wordlist, not masking regular @ !
    'ONLY >WID CURRENT !
    : @ NAME EVALUATE @ ; PREFIX IMMEDIATE
    : ! NAME EVALUATE ! ; PREFIX IMMEDIATE
    DEFINITINS \ Snap back.

    VARIABLE AAP
    12 !AAP
    @AAP .
    12 OK
    13 !AAP
    @AAP .
    13 OK

    Just saying.

    (I don't recommend this, by the way.)

    AFAICT the majority of HLL's use 'self-fetching' variables. Setting a >variable required something like := which corresponds to forth's TO.
    IMO local variables in forth was less about 'stack juggling' than
    simulating the 'look and feel' code of other languages. Forth locals
    code uses a fair number of TO's. Hugh once suggested locals ought to
    have used @ ! . This would have been very forth-like - but completely
    misses what locals aficionados were trying to do!

    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets >used. Without that distinction I'd find it hard justifying VALUEs - or >indeed know when to use them. By clearly stating their intent and usage, >they provide semantic value to written code and the language in general.
    But I'm not sure ANS ever did say - leaving users to muddle it out for >themselves. Locals' use of 'values' and TO only muddied the waters.

    With indirect code you can also do this, revealing that constants can
    be patched:

    This leads to

    Preliminary estamination to run test code.
    1000 CONSTANT SIZE
    Preliminary allocated buffer to run test code.
    CREATE BUFFIE SIZE CELLS ALLOT

    \ production code , pass size on the command line.
    : doit 1 ARG[] EVALUATE 'SIZE >DFA !
    'BUFFIE SIZE CELLS REALLOT ;

    The REALLOT serves a real purpose. In projecteuler problems
    buffers can be gigabytes. In a turnkey system they would
    land in the executable.

    Groetjes Albert


    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Apr 12 13:48:54 2026
    From Newsgroup: comp.lang.forth

    On 12-04-2026 04:49, dxf wrote:
    On 12/04/2026 6:03 am, albert@spenarnc.xs4all.nl wrote:
    In article <nnd$5fbdae9b$6428335d@7ddbf5ece7eb9625>,
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of. >>> Why, you ask? Because every name basically returns a pointer - unless we >>> DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word?
    Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or
    assignment is. Is the address known at compile time, we handle it like a >>> VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design. >>
    In ciforth you can do this:
    Prefixes ("recognizers") are supposed to be parsing the remainder
    lf tne word, like $DEADBEAT

    Abuse follows.

    \ In the minimal wordlist, not masking regular @ !
    'ONLY >WID CURRENT !
    : @ NAME EVALUATE @ ; PREFIX IMMEDIATE
    : ! NAME EVALUATE ! ; PREFIX IMMEDIATE
    DEFINITINS \ Snap back.

    VARIABLE AAP
    12 !AAP
    @AAP .
    12 OK
    13 !AAP
    @AAP .
    13 OK

    Just saying.

    (I don't recommend this, by the way.)

    AFAICT the majority of HLL's use 'self-fetching' variables. Setting a variable required something like := which corresponds to forth's TO.
    IMO local variables in forth was less about 'stack juggling' than
    simulating the 'look and feel' code of other languages.
    Without that distinction I'd find it hard justifying VALUEs - or
    indeed know when to use them. By clearly stating their intent and usage, they provide semantic value to written code and the language in general.
    But I'm not sure ANS ever did say - leaving users to muddle it out for themselves. Locals' use of 'values' and TO only muddied the waters.

    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely
    gets used.

    That's fun, you know! That's what I considered them when I created them!
    From the 4tH manual:

    "A value is a cross-over between a variable and a constant. (..) In many aspects, values behave like variables and can replace variables. The
    only thing you cannot do is make arrays of values. A value is not a
    literal expression either, so you can't use them to size arrays. In
    fact, a value is a variable that behaves in certain aspects like a
    constant."

    AFAICT the majority of HLL's use 'self-fetching' variables.

    Yeah. I know. I've been contemplating that when considering what my
    version of C-- would look like. The name from a variable would just
    return its pointer, so:

    int c;
    int b;

    c := 9;
    b := *c+5;

    Note c and b are rendered as pointers, *not* values. Which is equivalent to:

    variable c
    variable b

    9 c !
    c @ 5 + b !

    Yeah, := also fixes the "=" / "==" issue. Which I still have in
    uBasic/4tH. I mean:

    c = b = 10

    Doesn't assign 10 to b and c; it assigns the result of (b=10) to c
    (which if true equals to "1").

    Forth locals
    code uses a fair number of TO's. Hugh once suggested locals ought to
    have used @ ! . This would have been very forth-like - but completely misses what locals aficionados were trying to do!

    You can do both in 4tH, although the !/@ is the leanest of all implementations.

    Although in 4tH VALUEs and VARIABLEs are basically the same (4tH
    converts VARIABLES to VALUES - and vice versa, depending on the
    situation), I tend to use variables, unless I want to do initialization.

    Variables are much more flexible IMHO, because you can transfer their
    address without a hassle. And I don't particularly like parsing words.
    Or functional duplicates without any additional advantages. Or wasting
    two tokens I could have used for other stuff.

    VALUE is a thing I added to avoid the hassle of converting programs I
    port. Like ?DO, which I don't particularly like either. Two words in a
    loop making largely the same decision. Yeah. Great. Very clever.

    I love how bad designs and half assed concepts make their way into Forth
    and never get eradicated. Yeah. Love it.

    I mean - I've made some stupid design errors in my time. And at one
    point or another I always had to pay for that foolishness. Do you think
    it's fun adapting tens of programs, testing them before they are
    readmitted in the repository? Personally, I don't think so. But leaving
    that stuff in is worse IMHO.

    Hans Bezemer

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Apr 12 17:39:17 2026
    From Newsgroup: comp.lang.forth

    On 12-04-2026 12:13, albert@spenarnc.xs4all.nl wrote:
    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets
    used.

    In a sense, CONSTANTs are *almost* VALUEs:

    10 constant ten ok
    16 ' ten ! ok
    ten . 16 ok

    It won't work like that in 4tH (because ' ten would return "10"), but it
    works fine in most Forths since '78.

    Using this definition:

    : reconstant state @ if postpone ['] postpone ! else ' ! then ;
    immediate

    .. you could write:

    16 RECONSTANT ten

    .. and you'd *almost* have a VALUE. Cool, huh? :-)

    Hans Bezemer


    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Apr 13 10:54:34 2026
    From Newsgroup: comp.lang.forth

    On 13/04/2026 1:39 am, Hans Bezemer wrote:
    On 12-04-2026 12:13:
    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets >>> used. 

    In a sense, CONSTANTs are *almost* VALUEs:

    10 constant ten  ok
    16 ' ten !  ok
    ten . 16  ok

    It won't work like that in 4tH (because ' ten would return "10"), but it works fine in most Forths since '78.

    It probably needs a >BODY . Forth-in-ROM then no cigar. Inlining compilers?


    Using this definition:

      : reconstant state @ if postpone ['] postpone ! else ' ! then ; immediate

    .. you could write:

      16 RECONSTANT ten

    .. and you'd *almost* have a VALUE. Cool, huh?  :-)

    Do away with CONSTANTs and keep VALUEs ? :)

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Apr 13 12:13:08 2026
    From Newsgroup: comp.lang.forth

    In article <69db0856$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2026 6:03 am, albert@spenarnc.xs4all.nl wrote:
    In article <nnd$5fbdae9b$6428335d@7ddbf5ece7eb9625>,
    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    On 07-04-2026 13:35, albert@spenarnc.xs4all.nl wrote:
    A similar situation applies to "TO must scan". It turns out there
    is no standard program that can detect this. It steers implementation
    towards a scanning TO.

    Frankly, I consider VALUE one of these Forth errors we never got rid of. >>> Why, you ask? Because every name basically returns a pointer - unless we >>> DOES> something different.

    Sure, you can have different ways to store a value, but a parsing word?
    Really? And all of a sudden it should do different things depending on
    type? Yuk!

    Personally, I do VALUE and TO. But only for VALUE. And the compiler
    figures out what the most optimal way of handling this retrieval or
    assignment is. Is the address known at compile time, we handle it like a >>> VALUE, otherwise like a VARIABLE.

    And yeah, we have FTO and 2TO. I don't like it - but I like some
    smart@$$ "TO" even less. What a waste of code.. And what a horrible design. >>
    In ciforth you can do this:
    Prefixes ("recognizers") are supposed to be parsing the remainder
    lf tne word, like $DEADBEAT

    Abuse follows.

    \ In the minimal wordlist, not masking regular @ !
    'ONLY >WID CURRENT !
    : @ NAME EVALUATE @ ; PREFIX IMMEDIATE
    : ! NAME EVALUATE ! ; PREFIX IMMEDIATE
    DEFINITINS \ Snap back.

    VARIABLE AAP
    12 !AAP
    @AAP .
    12 OK
    13 !AAP
    @AAP .
    13 OK

    Just saying.

    (I don't recommend this, by the way.)

    AFAICT the majority of HLL's use 'self-fetching' variables. Setting a

    Not so algol 68. no l-value and r-values.
    real r;
    means that r is a name to designate a memory location where a real
    can be stored. r is of type "ref real" (5.4 is of type real , really).
    If a compiler sees
    a := b+c;
    It says, hmm a is the place where I can store the result of the calculation.
    In b+c it concludes that it cannot add references. So this is
    a coercion, forcing dereferencing a and b.
    This is a simular situation in the expression 5.1 + 17
    There is no module to add a fp to an integer. So 17 is widened to a
    fp number.


    variable required something like := which corresponds to forth's TO.
    IMO local variables in forth was less about 'stack juggling' than
    simulating the 'look and feel' code of other languages. Forth locals
    code uses a fair number of TO's. Hugh once suggested locals ought to
    have used @ ! . This would have been very forth-like - but completely
    misses what locals aficionados were trying to do!

    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets >used. Without that distinction I'd find it hard justifying VALUEs - or >indeed know when to use them. By clearly stating their intent and usage, >they provide semantic value to written code and the language in general.
    But I'm not sure ANS ever did say - leaving users to muddle it out for >themselves. Locals' use of 'values' and TO only muddied the waters.



    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Apr 13 19:24:15 2026
    From Newsgroup: comp.lang.forth

    On 13-04-2026 02:54, dxf wrote:
    On 13/04/2026 1:39 am, Hans Bezemer wrote:
    On 12-04-2026 12:13:
    For me at least, VALUEs are an 'almost CONSTANT' in which TO rarely gets >>>> used.

    In a sense, CONSTANTs are *almost* VALUEs:

    10 constant ten  ok
    16 ' ten !  ok
    ten . 16  ok

    It won't work like that in 4tH (because ' ten would return "10"), but it works fine in most Forths since '78.

    It probably needs a >BODY . Forth-in-ROM then no cigar. Inlining compilers?

    This is just plain gForth.. :-) Copied straight from the terminal.


    Do away with CONSTANTs and keep VALUEs ? :)

    Nah -- 4tH inlines all constants. And all compiled code in 4tH is R/O.
    In 4tH, VALUEs are obviously slower than CONSTANTs (see below). Not a
    good plan IMHO. ;-)

    Giving CONSTANTS an initial value, just like Forth-79 - fine;
    Dropping VALUEs (a lot more work after 30 years of doing it this way).
    Grrrr - alrighty then;
    Do away with CONSTANTs and keep VALUEs - NO!

    Hans Bezemer

    CODE (VALUE) DFREE (1); a = (cell) Object->Offset + OPERAND;
    VAR (a); DPUSH (Vars [(unsigned) a]); NEXT;

    CODE (LITERAL) DFREE (1); DPUSH (OPERAND); NEXT;






    --- Synchronet 3.21f-Linux NewsLink 1.2