• Fetch string from comment

    From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Mon Mar 3 18:17:01 2025
    From Newsgroup: comp.lang.forth

    String fetched from comment



    Comment string

    ( This string is a simple comment)
    ( The comment can be enhanced to include parethises in the string)

    ( This string is an (enhanced) comment)


    Accessing enhanced comments

    A comment string, when interpreting, can be found in the
    input buffer. It can be accessed and used if it's consumed
    or moved before the end of line.


    .( ( ccc<)> -- ) Print enhanced comment string

    cr i. .( This string, an enhanced comment, is consumed (gets printed))
    This string, an enhanced comment, is consumed (gets printed)


    s( ( ccc<)> -- s ) Save enhanced comment string

    s( "MOO") s( The sound of a cow)
    The above strings are saved in a ring buffer and
    return string references to be used soon.

    cr i. ul( tell ) tab tell
    The sound of a cow "MOO"


    ,( ( ccc<)> -- ) Compile enhanced comment string

    here ,( This string with '"bar" (foo)' is compiled)
    here om cr i. type
    This string with '"bar" (foo)' is compiled



    Notes


    i. Print "-->"
    ul(...) Underline output of enclosed code
    tell COUNT TYPE
    om OVER MINUS

    -fin-
    Note The underline didn't show in the post.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Mon Mar 3 19:44:14 2025
    From Newsgroup: comp.lang.forth

    On Mon, 3 Mar 2025 18:17:01 +0000, sjack wrote:

    om OVER MINUS

    Buddha said, om is boundless wisdom. ;-)

    For us poor novices, could you please share some Forth code
    to show how you have implemented your novel nestable comments?
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Tue Mar 4 16:08:49 2025
    From Newsgroup: comp.lang.forth

    On 4/03/2025 5:17 am, sjack wrote:
    String fetched from comment



    Comment string

    ( This string is a simple comment)
    ( The comment can be enhanced to include parethises in the string)

    ( This string is an (enhanced) comment)


    Accessing enhanced comments

    A comment string, when interpreting, can be found in the
    input buffer. It can be accessed and used if it's consumed
    or moved before the end of line.


    .( ( ccc<)> -- ) Print enhanced comment string

    cr i. .( This string, an enhanced comment, is consumed (gets printed))
    This string, an enhanced comment, is consumed (gets printed)


    s( ( ccc<)> -- s ) Save enhanced comment string

    s( "MOO") s( The sound of a cow)
    The above strings are saved in a ring buffer and
    return string references to be used soon.

    cr i. ul( tell ) tab tell
    The sound of a cow "MOO"


    ,( ( ccc<)> -- ) Compile enhanced comment string

    here ,( This string with '"bar" (foo)' is compiled)
    here om cr i. type
    This string with '"bar" (foo)' is compiled

    ...

    Not understanding where it fits in. Is this meant to be in lieu of
    ." ," S" etc ?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Mar 4 11:14:34 2025
    From Newsgroup: comp.lang.forth

    In article <vq4rmt$1dv1v$1@dont-email.me>, sjack <sdwjack69@gmail.com> wrote:
    String fetched from comment



    Comment string

    ( This string is a simple comment)
    ( The comment can be enhanced to include parethises in the string)

    ( This string is an (enhanced) comment)

    Nested comments is a source of a lot of evil, second only to
    premature optimisation and goto's.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Tue Mar 4 15:55:09 2025
    From Newsgroup: comp.lang.forth

    second only to premature optimisation and goto's.

    How to code a state-machine without goto's?

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Tue Mar 4 21:02:49 2025
    From Newsgroup: comp.lang.forth

    minforth <minforth@gmx.net> wrote:

    Buddha said, om is boundless wisdom. ;-)

    It's my favorite Forth word. When I type it, I become at peace.

    For us poor novices, could you please share some Forth code
    to show how you have implemented your novel nestable comments?

    Having a nested comment is nothing new; Forthers been doing it
    long back:
    : (
    ONE BEGIN
    INC@ CASE
    ZERO OF DROP ZERO ENDOF
    ASC ( OF 1+ ENDOF
    ASC ) OF 1- ENDOF
    ENDCASE
    DUP ONE < UNTIL
    DROP ; IMMEDIATE

    What may be new is the idea that if one has it then fetch it
    from the input buffer and use it for string operations.

    : @( PARSE_AREA [COMPILE] ( PARSE_AREA 1- OM ;

    : .( @( TYPE ; \ print it

    : S( @( SIB! ; \ stores in ring buffer

    Didn't bother to generalize the next two:

    Compile single line of text
    : ,(
    ONE BEGIN INC@ TUCK CASE
    ZERO OF 2DROP EXIT ENDOF
    ASC ( OF 1+ ENDOF
    ASC ) OF 1- ENDOF
    ENDCASE DUP WHILE SWAP C, REPEAT 2DROP ;

    -- Compile multiple lines of text
    : ,M(
    ONE BEGIN INC@ TUCK CASE
    ZERO OF SWAP DROP \N SWAP CR REFILL 0= IF ABORT THEN ENDOF
    ASC ( OF 1+ ENDOF
    ASC ) OF 1- ENDOF
    ENDCASE DUP WHILE SWAP C, REPEAT 2DROP ;

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Tue Mar 4 21:02:52 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> wrote:

    Not understanding where it fits in. Is this meant to be in lieu of
    ." ," S" etc ?

    It could be if you were so incline. I'm not suggesting you should but
    showing something possible.

    The case for enhanced (nested) comment:
    Traditionally the first line of an SCR is a comment seen by INDEX :
    ( FOO BAR BAT )
    Traditionally certain words are inclosed in parentheses, i.e. (.") .
    I would like to put such words in the comment seen by INDEX :
    ( FOO (PLUGH) BAR BAT )
    Hence to do so the simple comment is enhanced to allow this.

    Using enhanced comment for string operations:
    If you have it then use it if it suits you.
    The enhanced comment is more robust than the existing string operators
    that you show in that any mix of printable characters can be contained
    in the comment and string operators that base on it. No breaking up
    text nor escaping characters needed (by the Forth):

    .( The function("bar") char ) emit .( is to be used) \ standard, bah
    .( The function("bar") is to be used) \ enhanced, ok
    ." Jack said " char " emit ." boo" char " emit . \ standard, bah
    .( Jack said "boo") \ enhanced, ok
    @( echo -e "Hello World\!") /sys \ enhanced, ok
    --
    me
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Tue Mar 4 21:02:55 2025
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl wrote:

    Nested comments is a source of a lot of evil, second only to
    premature optimisation and goto's.

    Understandable for your case where you are developing and maintaing
    code for use by the general public that you would want to keep KISS
    and avoid at all possible cost of having to bail out some client
    who are apt to get themselves in trouble.
    In my case it poses no problem and I'm sure it won't for many others.
    --
    me
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Wed Mar 5 09:46:14 2025
    From Newsgroup: comp.lang.forth

    On 5/03/2025 8:02 am, sjack wrote:
    ...
    The enhanced comment is more robust than the existing string operators
    that you show in that any mix of printable characters can be contained
    in the comment and string operators that base on it. No breaking up
    text nor escaping characters needed (by the Forth):

    .( The function("bar") char ) emit .( is to be used) \ standard, bah
    .( The function("bar") is to be used) \ enhanced, ok
    ." Jack said " char " emit ." boo" char " emit . \ standard, bah
    .( Jack said "boo") \ enhanced, ok
    @( echo -e "Hello World\!") /sys \ enhanced, ok

    As " solutions go it has a charm to it. The code is nicely trivial
    albeit not idiot-proof ... ( ) needs to be balanced.

    For me the other issue was non-graphic characters. Unable to avoid it
    I adopted a simplified form of 200x escapes whereby " becomes \22 .

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Wed Mar 5 07:57:24 2025
    From Newsgroup: comp.lang.forth

    For the past 30 years, I got by with having .~ in addition to ." .
    The word .~ does the same ." but uses `~` as its delimiter.
    Most of my uses are served by judicious switching between ."
    and .~ .

    I am not a fan of S\" TYPE as it tends to move the parsing and
    interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility. For instance,
    having a backspace in a string has no obvious meaning in most
    of the system code, and an application can simply redefine BS
    to have it do what is necessary.

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Wed Mar 5 08:40:04 2025
    From Newsgroup: comp.lang.forth

    mhx@iae.nl (mhx) writes:
    I am not a fan of S\" TYPE as it tends to move the parsing and
    interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility.

    Can you elaborate on that, especially about the overhead?

    For instance,
    having a backspace in a string has no obvious meaning in most
    of the system code

    Nobody forces you you to use \b if it's inappropriate.

    and an application can simply redefine BS
    to have it do what is necessary.

    One would have to define BS first; otherwise you cannot redefine it.
    What is BS supposed to do, and what is redefining BS supposed to
    achieve?

    - 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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Wed Mar 5 20:16:33 2025
    From Newsgroup: comp.lang.forth

    On 5/03/2025 6:57 pm, mhx wrote:
    ...
    I am not a fan of S\" TYPE as it tends to move the parsing and
    interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility.

    What finally drove me to implement escapes was this:

    : RC$ ( -- a n ) \ row/col string
    bin? if s" \00" end s" 000" drop #asc ;

    Every other way of doing it looked like a hack. ... And it solved
    the embedded double-quote problem.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Mar 5 12:07:15 2025
    From Newsgroup: comp.lang.forth

    On 04/03/2025 15:55, mhx wrote:
    second only to premature optimisation and goto's.

    How to code a state-machine without goto's?

    -marcel

    A state transition table with an interpreter? See Julian Noble's paper http://galileo.phys.virginia.edu/classes/551.jvn.fall01/fsm.html

    But you probably knew about that so why doesn't it count as gotoless?
    --
    Gerry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Wed Mar 5 16:00:28 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> wrote:
    albeit not idiot-proof ... ( ) needs to be balanced.

    Yes, which is my most use case. An odd-ball unblanced () is still
    workable using the components, adding parenthesis to balance and
    adjusting the count for consumption:

    .( Use this when () are balanced )
    @( Use this when "foo(" left () unblanced)) 1- type

    For me the other issue was non-graphic characters. Unable to avoid it
    I adopted a simplified form of 200x escapes whereby " becomes \22 .

    That's another topic. Could be handled by enhanced comment but perhaps
    better delt with by other means.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Wed Mar 5 16:50:13 2025
    From Newsgroup: comp.lang.forth

    Gerry Jackson <do-not-use@swldwa.uk> writes:
    On 04/03/2025 15:55, mhx wrote:
    How to code a state-machine without goto's?
    ...
    But you probably knew about that so why doesn't it count as gotoless?

    Does it make a difference in understandability whether you implement a
    state transition as "goto state123" or in the Dijkstra-compatible
    "state = state123"? So why should I care whether it is gotoless?
    --
    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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Wed Mar 5 17:29:22 2025
    From Newsgroup: comp.lang.forth

    On Wed, 5 Mar 2025 16:50:13 +0000, Anton Ertl wrote:

    Does it make a difference in understandability whether you implement a
    state transition as "goto state123" or in the Dijkstra-compatible
    "state = state123"? So why should I care whether it is gotoless?

    The syntax is fine (the one is just as unreadable as the other) but what
    about the implementation?

    I couldn't locate the pertinent subject at https://www.cs.utexas.edu/~EWD/welcome.html, do you have a hint?

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Wed Mar 5 18:00:36 2025
    From Newsgroup: comp.lang.forth

    sjack <sjack@dontemail.me> wrote:

    .( Use this when () are balanced )
    @( Use this when "foo(" left () unblanced)) 1- type


    ( Using vocabulary for bacForth style )
    : .(( rtc back 1- type trek @( ;
    : .() rtc back 1 /+- type trek @( ;

    ( For non-diabetics:)
    cr i. .(( foo (bar) "bat(" ))
    foo (bar) "bat("

    cr i. .() (foo (bar) "bat)" )
    foo (bar) "bat)"
    --

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Wed Mar 5 18:29:48 2025
    From Newsgroup: comp.lang.forth

    Here's an example from Clojure:

    (let [saying3 (promise)]
    (future (deliver saying3 (wait 100 "Cheerio!")))
    @(let [saying2 (promise)]
    (future (deliver saying2 (wait 400 "Pip pip!")))
    @(let [saying1 (promise)]
    (future (deliver saying1 (wait 200 "'Ello, gov'na!")))
    (println @saying1)
    saying1)
    (println @saying2)
    saying2)
    (println @saying3)
    saying3)

    But Forth comments? But what do I know...
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Wed Mar 5 19:03:03 2025
    From Newsgroup: comp.lang.forth

    mhx@iae.nl (mhx) writes:
    On Wed, 5 Mar 2025 16:50:13 +0000, Anton Ertl wrote:

    Does it make a difference in understandability whether you implement a
    state transition as "goto state123" or in the Dijkstra-compatible
    "state = state123"? So why should I care whether it is gotoless?

    The syntax is fine (the one is just as unreadable as the other) but what >about the implementation?

    The argument about avoiding gotos have been along the lines that the
    goto makes it hard to understand the program, not that there was a
    problem with implementing it.

    I couldn't locate the pertinent subject at >https://www.cs.utexas.edu/~EWD/welcome.html, do you have a hint?

    https://dl.acm.org/doi/10.1145/362929.362947

    - 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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Wed Mar 5 19:40:32 2025
    From Newsgroup: comp.lang.forth

    On 05/03/2025 16:50, Anton Ertl wrote:
    Gerry Jackson <do-not-use@swldwa.uk> writes:
    On 04/03/2025 15:55, mhx wrote:
    How to code a state-machine without goto's?
    ...
    But you probably knew about that so why doesn't it count as gotoless?

    Does it make a difference in understandability whether you implement a
    state transition as "goto state123" or in the Dijkstra-compatible
    "state = state123"? So why should I care whether it is gotoless?


    I was just wondering why Marcel apparently cared, not you :)
    --
    Gerry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Wed Mar 5 23:43:05 2025
    From Newsgroup: comp.lang.forth

    I couldn't locate the pertinent subject at >>https://www.cs.utexas.edu/~EWD/welcome.html, do you have a hint?

    https://dl.acm.org/doi/10.1145/362929.362947

    That was a nice read! I see Dijkstra's argument that a goto as
    we know it is lacking necessary functionality.
    However, a state machine has well defined rules based on a
    state's stored information and its inputs, causing it to go to
    another well-defined state while generating outputs. In that
    context a goto is harmless and merely serves as a crutch when
    there are not enough computing nodes to serve all states in
    parallel. How to make such an efficient crutch in Forth?

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Mar 6 12:14:07 2025
    From Newsgroup: comp.lang.forth

    In article <74a5b61b65b89c594e3f653a0266dc874d6cc739@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 5/03/2025 6:57 pm, mhx wrote:
    ...
    I am not a fan of S\" TYPE as it tends to move the parsing and
    interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility.

    What finally drove me to implement escapes was this:

    : RC$ ( -- a n ) \ row/col string
    bin? if s" \00" end s" 000" drop #asc ;

    Every other way of doing it looked like a hack. ... And it solved
    the embedded double-quote problem.

    I don't understand this.
    "every other way to do what?".
    ( -- a n ) i s not a specification.
    If you introduce a word like RC$ tell us what it is supposed to
    do.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Mar 6 12:28:11 2025
    From Newsgroup: comp.lang.forth

    In article <001c29937cf8440ee5cc4a26135820af@www.novabbs.com>,
    mhx <mhx@iae.nl> wrote:
    I couldn't locate the pertinent subject at >>>https://www.cs.utexas.edu/~EWD/welcome.html, do you have a hint?

    https://dl.acm.org/doi/10.1145/362929.362947

    That was a nice read! I see Dijkstra's argument that a goto as
    we know it is lacking necessary functionality.
    However, a state machine has well defined rules based on a
    state's stored information and its inputs, causing it to go to
    another well-defined state while generating outputs. In that
    context a goto is harmless and merely serves as a crutch when
    there are not enough computing nodes to serve all states in
    parallel. How to make such an efficient crutch in Forth?

    The original Turing machine was a bunch of cards with instructions
    manipulating the tape.
    The last instruction was always the next card that you must get
    further instructions.
    As such the goto is underlying any type of stylized instructions.
    That was not what I meant that by
    "nested comment is almost as bad as goto's".
    I really meant that nested comment leads to a lot of confusion
    without redeeming advantages.


    -marcel

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Thu Mar 6 23:07:47 2025
    From Newsgroup: comp.lang.forth

    On 6/03/2025 10:14 pm, albert@spenarnc.xs4all.nl wrote:
    In article <74a5b61b65b89c594e3f653a0266dc874d6cc739@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 5/03/2025 6:57 pm, mhx wrote:
    ...
    I am not a fan of S\" TYPE as it tends to move the parsing and
    interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility.

    What finally drove me to implement escapes was this:

    : RC$ ( -- a n ) \ row/col string
    bin? if s" \00" end s" 000" drop #asc ;

    Every other way of doing it looked like a hack. ... And it solved
    the embedded double-quote problem.

    I don't understand this.
    "every other way to do what?".
    ( -- a n ) i s not a specification.
    If you introduce a word like RC$ tell us what it is supposed to
    do.

    The function in question is s" \00" which returns an adr/len string
    consisting of one byte whose value is $00.


    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Mar 6 18:09:30 2025
    From Newsgroup: comp.lang.forth

    mhx@iae.nl (mhx) writes:
    However, a state machine has well defined rules based on a
    state's stored information and its inputs, causing it to go to
    another well-defined state while generating outputs. In that
    context a goto is harmless and merely serves as a crutch when
    there are not enough computing nodes to serve all states in
    parallel. How to make such an efficient crutch in Forth?

    You lost me. Why would one "serve all states in parallel"?

    Anyway, if the question is how to implement a state machine
    efficiently in Forth, one answer is to stay at a higher, more
    structured level of abstraction or recreate it from the state machine.
    E.g., don't transform a regular expression into a (indeterministic or deterministic) finite state machine, but instead interpret it directly
    (that's what Bernd Paysan's regexp.fs does). Or instead of
    transforming a grammar into a push-down automaton, transform it into a structured Forth program (like Gray does).

    If you cannot do that, in standard Forth you don't really have good
    options. The best is probably to have the current state on the stack
    (probably in the form of the address of an array indexed with the
    input (or whatever causes a state change) and containing the potential
    next states at the appropriate elements.

    In a particular implementation, you can do more, including goto-like
    things. What I would do then is have a colon definition per state,
    and do the transition to the next state as tail call. Have some
    efficient forward-tail-call mechanism to allow calling states where
    the definition comes later. Gforth has a clever FORWARD, but for now
    that does not do tail-calls.

    - 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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Fri Mar 7 02:10:42 2025
    From Newsgroup: comp.lang.forth

    sjack <sjack@dontemail.me> wrote:
    String fetched from comment



    Notes


    i. Print "-->"
    ul(...) Underline output of enclosed code
    tell COUNT TYPE
    om OVER MINUS

    -fin-
    Note The underline didn't show in the post.


    OOPS, not MINUS but -
    : OM ( a1 a2 -- a1 u ) OVER - ;

    --
    me

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Fri Mar 7 08:27:33 2025
    From Newsgroup: comp.lang.forth

    On Thu, 6 Mar 2025 18:09:30 +0000, Anton Ertl wrote:

    mhx@iae.nl (mhx) writes:
    However, a state machine has well defined rules based on a
    state's stored information and its inputs, causing it to go to
    another well-defined state while generating outputs. In that
    context a goto is harmless and merely serves as a crutch when
    there are not enough computing nodes to serve all states in
    parallel. How to make such an efficient crutch in Forth?

    You lost me. Why would one "serve all states in parallel"?

    I was thinking on running a special kind of application
    (circuit simulation) on a GPU. [It is possible to transform
    circuits into a (big) digital wave filte (DWF, Fettweis).
    The advantage is that computation is parallel, with one
    result per clock cycle (no iteration needed). Because of
    the clock, the computations on each node can be done in
    parallel.]

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Fri Mar 7 12:23:46 2025
    From Newsgroup: comp.lang.forth

    On 06/03/2025 18:09, Anton Ertl wrote:
    mhx@iae.nl (mhx) writes:
    However, a state machine has well defined rules based on a
    state's stored information and its inputs, causing it to go to
    another well-defined state while generating outputs. In that
    context a goto is harmless and merely serves as a crutch when
    there are not enough computing nodes to serve all states in
    parallel. How to make such an efficient crutch in Forth?

    You lost me. Why would one "serve all states in parallel"?

    Anyway, if the question is how to implement a state machine
    efficiently in Forth, one answer is to stay at a higher, more
    structured level of abstraction or recreate it from the state machine.
    E.g., don't transform a regular expression into a (indeterministic or deterministic) finite state machine, but instead interpret it directly (that's what Bernd Paysan's regexp.fs does). Or instead of
    transforming a grammar into a push-down automaton, transform it into a structured Forth program (like Gray does).

    If you cannot do that, in standard Forth you don't really have good
    options. The best is probably to have the current state on the stack (probably in the form of the address of an array indexed with the
    input (or whatever causes a state change) and containing the potential
    next states at the appropriate elements.

    In a particular implementation, you can do more, including goto-like
    things. What I would do then is have a colon definition per state,
    and do the transition to the next state as tail call. Have some
    efficient forward-tail-call mechanism to allow calling states where
    the definition comes later. Gforth has a clever FORWARD, but for now
    that does not do tail-calls.

    - anton

    About a year ago I wanted a finite state machine and thought that the
    Julian Noble approach was rather slow, so I developed a different
    approach that I haven't seen elsewhere. This method defines a state of
    the FSM as a wordlist that contains an action including a test, (a
    :noname definition), and a VALUE that holds the execution token of the
    state's action/test.

    A simple example that demonstrates the principle is given below, it
    implements the Michael Gassanenko example that selects integers that can
    be divided by 6. See https://groups.google.com/g/comp.lang.forth/c/iHCT2IaqxSA/m/85IUu0GSBwAJ
    for another implementation. An FSM for the /6 example is not the best
    solution for the example but is simply used to demonstrate the principle.

    Use of a wordlist, whose wid is held in an immediate constant, enables
    easy linkage between states at compile time, eg a typical state action
    in outline is:

    :noname <action>
    if state-x [ >order ] next-state [ previous ]
    else state-y [ >order ] next-state [ previous ]
    ; this-state >order to next-state previous

    where
    - next-state is the VALUE holding the states action xt. A common name is
    used for each state so that code can be factored out.
    - state-x and state-y are the immediate constants holding the state's wordlist.
    - the wordlist switching is factored out for readability

    Advantages are:
    - the FSM run time loop is simple
    - wordlist switching only occurs at compile time
    - forward reference is easy because state wordlists and a common name
    for the action-xt VALUEs are defined at the start.
    - easily extendable for states that can goto to several other states
    e.g. use a CASE statement for the state action.
    - I believe but haven't proved that the run time code could be
    automatically generated by defining a simple state transition table

    Disadvantages are:
    - the Forth code doesn't give much idea of the overall operation of the
    FSM (probably true for FSMs in general)
    - the state wordlists are redundant at run time

    \ The example
    : fsm-state ( "state-name" "action-name" -- )
    get-current
    wordlist dup constant immediate set-current 0 value
    set-current
    ;

    \ state name state action-xt
    \ ~~~~~~~~~~ ~~~~~~~~~~~~~~~
    fsm-state inc-n next-state
    fsm-state /2 next-state
    fsm-state /3 next-state
    fsm-state .n next-state

    : is-next-state ( wid -- )
    >order s" next-state" evaluate previous
    ; immediate

    0 constant stop-fsm

    :noname ( ad -- ad xt|0 )
    dup 1 over +! 2@ >=
    if /2 is-next-state else stop-fsm then
    ; inc-n >order to next-state previous

    :noname ( ad -- ad xt )
    dup @ 2 mod if inc-n is-next-state else /3 is-next-state then
    \ No, the two IS-NEXT_STATEs can't be replaced by one after the THEN
    ; /2 >order to next-state previous

    :noname ( ad -- ad xt )
    dup @ 3 mod if inc-n is-next-state else .n is-next-state then
    ; /3 >order to next-state previous

    :noname ( ad -- ad xt )
    dup @ . ( drop ) inc-n is-next-state
    ; .n >order to next-state previous

    : run-fsm ( ad xt -- ) begin dup while execute repeat 2drop ;

    2variable counter

    inc-n >order next-state constant start previous

    : /6? ( n -- )
    cr cr 0 counter 2!
    counter start run-fsm
    ;

    78 /6? \ displays 6 12 18 24 30 36 42 48 54 60 66 72 78
    --
    Gerry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Mar 7 14:52:02 2025
    From Newsgroup: comp.lang.forth

    In article <2025Mar5.094004@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    mhx@iae.nl (mhx) writes:
    I am not a fan of S\" TYPE as it tends to move the parsing and >>interpretation problems to parts of the code / library that may
    not be prepared for it, or where it would be quite an overhead
    to anticipate every present and future possibility.

    Can you elaborate on that, especially about the overhead?

    For instance,
    having a backspace in a string has no obvious meaning in most
    of the system code

    Nobody forces you you to use \b if it's inappropriate.

    That is not the problem with escapes.
    The problem comes if you use "\b" where it is meant literal
    and it is altered.
    So beside adhering to ISO, the string constant in style
    "orang utan@@\a\b\q#$^^&**()^*()_+" are absolutely literal
    in ciforth. The "-prefix was a pre-20xx extension.
    Only exception is the doubling of the double quotes, Algol68 style. "orang""UTAN" replace "orang\"UTAN" without the possibility of
    confusion.


    and an application can simply redefine BS
    to have it do what is necessary.

    One would have to define BS first; otherwise you cannot redefine it.
    What is BS supposed to do, and what is redefining BS supposed to
    achieve?

    Good questions.
    My idea of a prefix that does special parsing:
    1. it is part of the application and documented there
    2. User defined notation must not be recognized in the minimum defined
    search order, such like numbers. Instead it belongs in Forth or another wordlist and is forgettable, marked-offable.

    In this context these questions are easily answered.


    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Mar 9 16:29:23 2025
    From Newsgroup: comp.lang.forth

    Gerry Jackson <do-not-use@swldwa.uk> writes:
    Use of a wordlist, whose wid is held in an immediate constant, enables
    easy linkage between states at compile time, eg a typical state action
    in outline is:

    :noname <action>
    if state-x [ >order ] next-state [ previous ]
    else state-y [ >order ] next-state [ previous ]
    ; this-state >order to next-state previous

    It means that Gforth will have to improve its SEE in order to point
    out the differences between the different NEXT-STATEs. Currently I get:

    /2 >order ok
    next-state xt-see
    noname :
    dup @ #1 and
    IF next-state
    ELSE next-state
    THEN ; ok

    Disadvantages are:
    - the Forth code doesn't give much idea of the overall operation of the
    FSM (probably true for FSMs in general)

    That's definitely the case here. IIRC for Michael Gassanenko it was a demonstration of filtering and backtracking, but it's unclear to me
    how that transfers to FSMs.

    Anyway, let's look at the core:

    : run-fsm ( ad xt -- ) begin dup while execute repeat 2drop ;

    This means that every state has to return to this loop to dispatch the
    next one. Now Gforth (development) has EXECUTE-EXIT, which allows
    tail-calling the next state for better efficiency.

    I have worked out an example: https://www.complang.tuwien.ac.at/forth/programs/fsm-ae.4th

    Let's first look at the example: The example recognizes and prints
    numbers in a text and ignores everything else. It terminates when it
    sees '$'. It has two states, one for being inside a number and one
    for outside:

    state outside-num
    state inside-num

    (Note that this is not the standar Forth word STATE).

    Then we define transitions:

    : out->out ( c-addr -- c-addr1 )
    count outside-num transition ;

    ' out->out outside-num all-transitions

    The out->out transition is the simplest one: It fetches the next char
    (with COUNT) and switches to OUTSIDE-NUM. TRANSITION already starts
    the dispatch for that state and the next char; this (and maybe also
    COUNT) could be put in the general FSM interpreter (START-DFA), but by
    having TRANSITION in the individual transition actions (e.g.,
    OUT->OUT), the implementation is more flexible, as we will see.

    At first OUT->OUT is put in transitions from OUTSIDE-NUM for all
    characters using ALL-TANSITIONS; later the transitions of various
    characters are overwritten:

    ' out->in '9' 1+ '0' outside-num some-transitions
    ' out->stop '$' outside-num one-transition

    Note that the stack effect comment for out->out is from the start of
    the word to the start of the next state-transition word; the actual
    stack effect depends on the implementation of transition.

    For more state transitions and the corresponding transition words see
    the source code.

    Example usage:

    s" 123 abc 456 df$" drop outside-num start-dfa \ prints "123 456"

    Now for the implementations: States are just arrays of xts, indexed by
    the character, and the xt is that of the transition from the state
    with that character.

    The implementation without EXECUTE-EXIT looks as follows:

    : transition ( c addr -- xt )
    \ addr specifies the next state
    ]] swap th @ [[ ; immediate

    : stop ( c-addr -- 0 )
    drop 0 ;

    : start-dfa ( c-addr addr -- )
    swap count rot transition
    begin ( ... xt )
    execute dup
    0= until
    drop ;

    TRANSITION could be a plain colon definition here, but it is a macro
    in order to make it more competetive in Gforth with the EXECUTE-EXIT
    variant. Here the termination is performed by replacing the next
    c-addr with 0 and testing for 0 in the loop.

    An alternative implementation is to use EXECUTE-EXIT to tail-call the
    next transition:

    : transition ( c addr -- )
    ]] swap th @ execute-exit [[ ; immediate

    : stop ( -- )
    \ let the ";" behind the STOP do the stopping
    ]] drop [[ ; immediate

    : start-dfa ( c-addr addr -- )
    \ let the dfa work on the string starting at c-addr, with initial
    \ state addr
    swap count rot transition ;

    Here TRANSITION contains the EXECUTE in the form of EXECUTE-EXIT, and
    so each transition word directly calls the next one, and no loop is
    necessary; with EXECUTE this would fill the return stack after a few
    thousand transitions, but EXECUTE-EXIT takes the return address off
    the return stack before EXECUTEing the next word and therefore can
    perform an indefinite number of state transitions.

    So how do we get out of the state machine? By not performing a
    transition; instead we simply return to the caller of START-DFA.

    I looked at the generated code and thought that we can get rid of the
    SWAP in the transition code by using the generalized constant folding
    feature of Gforth. This replaces the definition of TRANSITION with:

    : noopt-transition-compile, ( xt -- )
    \ basic compile, implementation for TRANSITION
    drop ]] swap th @ execute-exit [[ ;

    : 1opt-transition-compile, ( xt -- )
    drop lits> ]] cells literal + @ execute-exit [[ ;

    `noopt-transition-compile, 1 foldn: transition-compile,
    `1opt-transition-compile, 1 set-fold#

    : transition ( c addr -- )
    \ dispatches the transition code for char C in state ADDR. The
    \ stack effect describes the state of the stack when the xt has
    \ been consumed, not when the EXECUTE-EXIT returns, if at all;
    \ either compile, or execute-exit this word in order to achieve
    \ tail-call optimization
    [ 0 noopt-transition-compile, ] ;
    ' transition-compile, set-optimizer

    The NOOPT-TRANSITION-COMPILE, implementation is used when TRANSITION
    is compiled without a preceding constant, 1OPT-TRANSITION-COMPILE, is
    used when 1 or more constants precede the compilation of TRANSITION.
    In the latter case code without the SWAP is generated.

    How fast are the variants. I have a benchmark that performs 1M
    iterations of processing a string of 100 non-digits (last char is '$',
    of course), and one where the processed string contains numbers. The
    latter just takes more instructions and cycles, but the former just
    performs 99 OUT->OUT transitions in each iteration and shows the basic performance of the whole scheme.

    Here are the results on a Zen4:

    loop plain optimized implementation variant 1_278_763_454 1_175_241_846 1_175_505_964 cycles
    3_651_376_357 2_441_376_030 2_045_832_844 instructions

    "loop" is the version that has a loop; the others are the EXECUTE-EXIT variants, "plain" uses the macro, "optimized" tries to do better by
    recognizing that there is a constant in play. While "optimized" saves
    4 instructions per transition compared to "plain", it does not save
    cycles. Overall the number of cycles is quite high given the number
    of instructions and the capabilities of the CPU. I'll take a look at
    it below. The loop variant costs 12 instructions and 1 cycle per
    transition more than the plain variant.

    Here's the code for OUT->OUT:

    plain optimized
    count 1->2 count 1->2
    mov rax,r8 mov rax,r8
    add r8,$01 add r8,$01
    movzx r15d,byte PTR [eax] movzx r15d,byte PTR [eax]
    lit 2->3 cells 2->2
    outside-num shl r15,$03
    mov r9,$10[rbx] lit+ 2->2
    swap 3->3 outside-num
    mov rax,r15 add r15,$18[rbx]
    mov r15,r9 @ 2->2
    mov r9,rax mov r15,[r15]
    cells 3->3 execute-;s 2->1
    shl r9,$03 add rbx,$30
    + 3->2 mov rbx,$00[r13]
    add r15,r9 mov rax,-$10[r15]
    @ 2->2 mov rdx,r15
    mov r15,[r15] add r13,$08
    execute-;s 2->1 sub rbx,$08
    add rbx,$40 jmp eax
    mov rbx,$00[r13]
    mov rax,-$10[r15]
    mov rdx,r15
    add r13,$08
    sub rbx,$08
    jmp eax

    You see only 13 instructions in OPTIMIZED here. The jump first leads
    to DOCOL (6 instructions) before enterin this code again.

    For now I don't see why the whole thing takes so many cycles. I'll
    take a closer look later.

    - 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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Gerry Jackson@do-not-use@swldwa.uk to comp.lang.forth on Mon Mar 10 11:49:26 2025
    From Newsgroup: comp.lang.forth

    On 09/03/2025 16:29, Anton Ertl wrote:
    Gerry Jackson <do-not-use@swldwa.uk> writes:
    Use of a wordlist, whose wid is held in an immediate constant, enables
    easy linkage between states at compile time, eg a typical state action
    in outline is:

    :noname <action>
    if state-x [ >order ] next-state [ previous ]
    else state-y [ >order ] next-state [ previous ]
    ; this-state >order to next-state previous

    It means that Gforth will have to improve its SEE in order to point
    out the differences between the different NEXT-STATEs. Currently I get:

    /2 >order ok
    next-state xt-see
    noname :
    dup @ #1 and
    IF next-state
    ELSE next-state
    THEN ; ok
    :) Well if you've never encountered this in (how many years has GForth
    been going - 25/30?) it's haardly worth bothering. At least it make
    someone think something strange is going on.


    Disadvantages are:
    - the Forth code doesn't give much idea of the overall operation of the
    FSM (probably true for FSMs in general)

    That's definitely the case here.

    THe same applies to your example. Most FSM implementations have a
    transition table and/or a state diagram.

    IIRC for Michael Gassanenko it was a
    demonstration of filtering and backtracking,

    That's correct. I said it was a simple example of an FSM to demonstrate
    the principle the FSM

    but it's unclear to me
    how that transfers to FSMs.

    The transition table for my example is:
    Next State
    State If test true If test false
    ----- ------------ -------------
    inc-n /2 exit FSM
    /2 inc-n /3
    /3 inc-n .n
    .n inc-n inc-n

    As posts are text only it's not suitable for a state diagram.


    Anyway, let's look at the core:

    : run-fsm ( ad xt -- ) begin dup while execute repeat 2drop ;

    This means that every state has to return to this loop to dispatch the
    next one. Now Gforth (development) has EXECUTE-EXIT, which allows tail-calling the next state for better efficiency.

    You know more about effects of an instruction cache than me bu wouldn't
    a short loop like that be likely to fit in a cache line?

    Your example with EXECUTE-EXIT made me think that I ought to be able to
    change mine to include an R> DROP at the start of each state to get the
    same effect and eliminate the loop. Non-standard of course, slower but apparently more portable. Possibly replacing the NEXT-STATE value with a common deferred word to handle forward definitions as before..


    I have worked out an example: https://www.complang.tuwien.ac.at/forth/programs/fsm-ae.4th

    Got to go but I'll return to this and look at your example in more
    detail later today hopefully.

    [...]


    - anton
    --
    Gerry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Tue Mar 11 09:53:42 2025
    From Newsgroup: comp.lang.forth

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    Here are the results on a Zen4:

    loop plain optimized implementation variant
    1_278_763_454 1_175_241_846 1_175_505_964 cycles
    3_651_376_357 2_441_376_030 2_045_832_844 instructions
    ...
    For now I don't see why the whole thing takes so many cycles. I'll
    take a closer look later.

    It seems to be an interaction between microarchitectural
    corner-cutting in Zen4 and the way that Gforth is implemented, see <2025Mar11.091817@mips.complang.tuwien.ac.at> and <2025Mar10.181427@mips.complang.tuwien.ac.at> in comp.arch.

    So let's measure on Golden Cove (Intel 1315U P-Core) which apparently
    does not have that problem, at least not for the "dup execute-exit" microbenchmark I used in those measurements. For the fsm-ae.4th
    bench1 benchmark I see the following, however:

    loop plain optimized implementation variant 1_193_518_309 1_284_084_677 1_282_838_710 cycles
    3_755_406_062 2_445_475_893 2_049_460_804 instructions

    I.e., the plain and optimized variants are even slower than on Zen4,
    and the loop version is not just faster than on Zen4, but even faster
    than plain and optimized. To see why that is, here's the out->out code followed by the docol code:

    count 1->2
    mov rax,r8
    add r8,$01
    movzx r15d,byte PTR [eax]
    cells 2->2
    shl r15,$03
    lit+ 2->2
    outside-num
    0-6 add r15,$18[rbx]
    @ 2->2
    6-11 mov r15,[r15]
    execute-;s 2->1
    add rbx,$30
    mov rbx,[r14]
    mov rax,-$10[r15]
    11-11 mov rdx,r15
    add r14,$08
    sub rbx,$08
    jmp eax

    add rbx,$08
    sub r14,$08
    mov [r14],rbx
    11-11 mov rbx,rdx
    mov rax,[rbx]
    jmp eax

    In the benchmark the out->out code jumps to docol and docol jumps to
    out->out in 99/100 cases.

    I see a depence loop here that works through the instructins where I
    have added some annotations like "0-6" in front. 0-6 means that with
    rbx available in cycle 0, the result is available in r15 in cycle 6 (5
    cycles from the load, 1 from the addition). The next instruction in
    the chain depends on that result in r15 and produces another result in
    r15. Then we have mov instructions that move the result into rdx and
    finally into rbx where it enters the sequence again.
    Register-register mov instructions usually consume no cycles on the
    Golden Cove, so they are counted with 0 cycles here.

    My computation explains 11 cycles per iteration, but not the measured
    12; I may be unaware of another source of delay, or some other
    dependence chain may be the reason; I am pretty sure that I have the
    right one, though, especially because the results with "dup
    execute-exit" eliminate this particular dependence chain and run at
    2.4 cycles per iteration on the Golden Cove.

    I also let llvm-mca (microarchitectural analysis) have a go at it, and
    it assumes 1 cycle latency for the register-register moves, and
    reports:

    [~:156499] cat tmp/yyy.s |llvm-mca-16 -mcpu=alderlake --iterations=1000 -timeline
    Iterations: 1000
    Instructions: 19000
    Total Cycles: 13019
    Total uOps: 12000

    So it claims that this sequence should take 13 cycles per iteration.

    It also gives various other information but I find that hard to
    interpret.

    - 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 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2