• Re: Nested definitions

    From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Jul 7 14:31:03 2025
    From Newsgroup: comp.lang.forth

    On 03-07-2025 18:47, Ruvim wrote:
    On 2025-07-03 17:11, albert@spenarnc.xs4all.nl wrote:
    In article <1043831$3ggg9$1@dont-email.me>,
    Ruvim-a <ruvim.pinka@gmail.com> wrote:
    On 2025-07-02 15:37, albert@spenarnc.xs4all.nl wrote:
    In article <1042s2o$3d58h$1@dont-email.me>,
    Ruvim-a <ruvim.pinka@gmail.com> wrote:
    On 2025-06-24 01:03, minforth wrote:
    [...]

    For me, the small syntax extension is a convenience when working
    with longer definitions. A bit contrived (:= synonym for TO):

    : SOME-APP { a f: b c | temp == n: flag z: freq }
    \ inputs: integer a, floats b c
    \ uninitialized: float temp
    \ outputs: integer flag, complex freq
    -a-a -a<: FUNC < ... calc function ... > ;>

    BTW, why do you prefer the special syntax `<: ... ;>`
    over an extension to the existing words `:` and `;`

    -a-a-a : SOME-APP
    -a-a-a-a-a-a [ : FUNC < ... calc function ... > ; ]
    -a-a-a-a-a-a < ... >
    -a-a-a ;

    In this approach the word `:` knows that it's a nested definition and >>>>> behaves accordingly.

    Or it has not even know it, if [ is smart enough to compile a jump to
    after ].

    This can be tricky because the following should work:

    -a-a create foo [ 123 , ] [ 456 ,

    -a-a : bar-a [ ' foo compile, 123 lit, ] ;

    If this bothers you, rename it in [[ ]].

    Once we enhance [ ] to do things prohibited by the standard,
    (adding nested definitions) I can't be bothered with this too much.


    The standard does not prohibit a system from supporting nested
    definitions in whichever way that does not violate the standard behavior.


    Yes, something like "private[ ... ]private" is a possible approach, and
    its implementation seems simpler than adding the smarts to `:` and `;`
    (and other defining words, if any).

    The advantage of this approach over "<: ... ;>" is that you can define
    not only colon-definitions, but also constants, variables, immediate
    words, one-time macros, etc.


    -a : foo ( F: r.coefficient -- r.result )
    -a-a-a private[
    -a-a-a-a-a variable cnt
    -a-a-a-a-a 0e fvalue k
    -a-a-a-a-a : [x] ... ; immediate
    -a-a-a ]private
    -a-a-a to k-a-a 0 cnt !
    -a-a-a ...
    -a ;

    It's also possible to associated the word list of private words with the containing word xt for debugging purposes.

    4tH has always allowed it, since it considered : and ; as branches -
    like AHEAD. Since [: and ;] are just :NONAME and ; aliases they work essentially the same.

    I never used it, because it would cause portability issues - and I
    considered it "bad style".

    The same goes for allocation (VARIABLE, VALUE, STRING, ARRAY). These are
    in 4tH basically just directives - NOTHING IS ACTUALLY ALLOCATED. That
    works just fine.

    So the whole shebang would practically work out of the box. But of
    course, to follow the complete example, I had to do the FP stuff as well
    - and I wanted to do a bit of protecting the words between the tags.

    In short, that boils down to this (for FOO):

    1018| branch 1036 foo
    1019| literal 1020
    1020| branch 1030 <== jump after opcode 1030
    1021| literal 0 <== mantissa 0
    1022| literal 0 <== exponent 0
    1023| variable 2 *k_f
    1024| call 0 2!
    1025| branch 1027 k <== DOES> definition
    1026| variable 2 *k_f
    1027| branch 7 2@ <== end DOES> def.
    1028| branch 1029 [x]
    1029| exit 0
    1030| exit 0 <== end of "private"
    1031| drop 0 <== drop the XT
    1032| variable 2 *k_f
    1033| call 0 2!
    1034| literal 0
    1035| to 1 cnt
    1036| exit 0

    Which is the compilant of this (preprocessor) code:

    :macro ... ;
    :macro private[ [: ;
    :macro ]private ;] drop ;
    :macro 0e 0 S>F ;

    include lib/fp1.4th
    include 4pp/lib/fvalue.4pp

    : foo ( F: r.coefficient -- r.result )
    private[
    variable cnt
    0e fvalue k
    : [x] ... ; immediate
    ]private
    fto k 0 cnt !
    ...
    ;

    100 s>f foo k f. cnt ? cr

    The weird code generated from 1021 - 1027 is the result of this code (generated by the preprocessor):

    0 S>F FLOAT ARRAY k
    AKA k *k_f LATEST F! :REDO k F@ ;

    1. FP "zero" is thrown on the stack;
    2. A variable with the capacity of a "float" is created (FVARIABLE);
    3. Copy that symbol in the symbol table;
    4. Initialize the FP variable;
    5. Create a "DOES>" definition that fetches that value.

    But it *does* work as advertised..

    Hans Bezemer
    --- Synchronet 3.21a-Linux NewsLink 1.2