Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #134925 > unrolled thread

ciforth model

Started byalbert@spenarnc.xs4all.nl
First post2026-04-16 15:38 +0200
Last post2026-04-17 12:13 +0200
Articles 20 on this page of 25 — 8 participants

Back to article view | Back to comp.lang.forth


Contents

  ciforth model albert@spenarnc.xs4all.nl - 2026-04-16 15:38 +0200
    Re: ciforth model dxf <dxforth@gmail.com> - 2026-04-17 11:44 +1000
      Re: ciforth model anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-04-17 07:29 +0000
        Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-17 12:10 +0200
          Re: ciforth model anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-04-18 10:26 +0000
            Re: ciforth model peter <peter.noreply@tin.it> - 2026-04-18 18:11 +0200
            Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-18 20:57 +0200
              Re: ciforth model anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-04-19 11:08 +0000
                Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-20 13:39 +0200
            Re: ciforth model peter <peter.noreply@tin.it> - 2026-05-21 10:28 +0200
              Re: ciforth model minforth <minforth@gmx.net> - 2026-05-22 12:04 +0200
              Re: ciforth model anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-05-23 18:12 +0000
                Re: ciforth model peter <peter.noreply@tin.it> - 2026-05-23 23:09 +0200
                Re: ciforth model peter <peter.noreply@tin.it> - 2026-05-24 10:07 +0200
                  Re: ciforth model anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-05-25 13:34 +0000
                    Re: ciforth model peter <peter.noreply@tin.it> - 2026-05-27 10:42 +0200
        Re: ciforth model Hans Bezemer <the.beez.speaks@gmail.com> - 2026-04-21 19:39 +0200
        Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-22 22:48 +0200
          Re: ciforth model Paul Rubin <no.email@nospam.invalid> - 2026-04-24 10:38 -0700
            Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-25 11:54 +0200
              Re: ciforth model Paul Rubin <no.email@nospam.invalid> - 2026-04-25 13:22 -0700
                Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-26 14:05 +0200
        hashing for Forth dictionaries and address books (was Re: ciforth model) Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-01 15:09 -0300
    Re: ciforth model Paul Rubin <no.email@nospam.invalid> - 2026-04-17 00:27 -0700
      Re: ciforth model albert@spenarnc.xs4all.nl - 2026-04-17 12:13 +0200

Page 1 of 2  [1] 2  Next page →


#134925 — ciforth model

Fromalbert@spenarnc.xs4all.nl
Date2026-04-16 15:38 +0200
Subjectciforth model
Message-ID<nnd$2bd819ed$5423e023@908ce2ca63477284>
The cimodel is based on a memory map that is well defined.

The most important difference from all preceding models is the
central role of the dictionary entry concept.
The dictionary is subdivided into mutually exclusive entries
with no other data.

Memory model

- os system header (or disk boot code)
- boot code
- bespoke dictionary
    - dictionary entries
           - header
           - memory possessed by the previous header
HERE
- free dictionary
- task frame
- buffers

There is a HIP (high level interpreter pointer) that points to high
level code. NEXT executes the dictionary entry pointed to by HIP.

Only the part up till HERE is present in the executable.

os system header is the obligatory os dependant code to make the
file loadable by the os. (Or boot from disk.)
Possibly definitions of segments are to be found here.

boot code
The boot code contains a safeguard of the external interface,
for example the parameters that are passed to an executable.
Then it initializes the data stack pointer DSP , the return stack pointer RSP,
and the high level interpreter pointer HIP, and possibly
other register initialisation for special purposes.
It imposes a structure on the task frame and possibly buffers based on
pertinent data that is stored in so called user variables.
(In order to save the system, user variables are changed
to reflect the new state of the system.)
The HIP is made to point to the first command
of the word COLD. Then this first command is executed,
which is indicated by "doing NEXT".

Bespoke dictionary
The reserved part of the dictionary is subdivided in dictionary
entries.
A d.e. is
- name (string, i.e. possibly variable length)
- Fixed size field, normally the cell-size of the current Forth
  - C  Code pointer to what can be executed.
  - D  Data pointer to what can be fetched or stored.
  - F  A bit  array of flags, e.g. immediate flag.
  - L  Link information to other dictionary entries.
  - N  Contains a name or points to a name
    And possibly optional CELLS like
  - S  Points to source code
  - X  Whatever serves
- Data possessed by the preceding entry.
  This data may be machine code, interpreted code or plain data.

Free dictionary
The free dictionary can be allocated and then becomes bespoke.
Strings, functions, buffers, and headers all can be allocated.

Task frame
A task frame consist of a data stack, terminal input buffer,
return stack and user variables.
This is called thusly because it is replicated if multiple
task are running concurrently.
Note that the data stack can run down to HERE, like in the FIG-model.

The buffers
The buffers are 1 Kbyte buffers. They are used for a block
system, that plays an important role as a library.
They are locked and unlocked while in use and can serve
for nested includes for files, as well.

Indirect threading model.
A pointer to the first fixed field of a header is called dea,
dictionary entry address.
Indirect threaded code means that the program counter is loaded
with the C field of a dea, so effecting an indirect jump to
the C-field.

An entry is identified by the handle. All manipulation and properties
of "definitions", "words", "functions", "buffers" is referring to by
this address.
Instead of having a plethora of relation between different fields,
one finds properties of a dea by passing through the fields.


A dea containing a low level definition has a pointer to machine code
in C.

A variable or buffer contains code that returns the content
of the D field pointing to storage (in general directly
after the header.)
A constant contains code that returns the content of the
D field, where there is no implication of that being a pointer.

A high level definition contains a pointer to a specific
machine code called DOCOL in C.
The D pointer points to an area (in general directly after
the header) where a sequence of dea's is stored.
Execution the definition means executing these dea's in order.

An object (CREATE DOES> construct) contains a pointer to specific
machine code called DODOES in C.
The D pointer points to an area where a pointer to the DOES>
code resides, followed by a data area.

ANNEX
In the 64 bits era a string constant is
 - a cell containing the length in bytes
 - string itself, not necessarily one char per byte.
 - alignment to 8 bytes.
All fields are one cell.

However we could squeeze for 16 bits, without logically affecting the model.

code field: one byte, an offset to a code area of 256 bytes.
data field: 16 bit pointer
name filed: 4 byte, 3 first and last char. Only 7 bits,
            8th bit counts are flags
flag field: hidden in the name
link field: 256 bit offset, d.e. are at most 256 byte long.
The total of 8 bytes will put even the original fig model to shame.
-- 
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.

[toc] | [next] | [standalone]


#134926

Fromdxf <dxforth@gmail.com>
Date2026-04-17 11:44 +1000
Message-ID<69e19091$1@news.ausics.net>
In reply to#134925
On 16/04/2026 11:38 pm, albert@spenarnc.xs4all.nl wrote:
> ... 
> However we could squeeze for 16 bits, without logically affecting the model.
> 
> code field: one byte, an offset to a code area of 256 bytes.
> data field: 16 bit pointer
> name filed: 4 byte, 3 first and last char. Only 7 bits,
>             8th bit counts are flags
> flag field: hidden in the name
> link field: 256 bit offset, d.e. are at most 256 byte long.
> The total of 8 bytes will put even the original fig model to shame.

Don't know who was first but Fig-forth's variable length names is something
that Forth Inc and pretty much everyone adopted.  Moore attempted to defend
'3 chars plus count' but to no avail.  That ship had sailed.
 

[toc] | [prev] | [next] | [standalone]


#134928

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2026-04-17 07:29 +0000
Message-ID<2026Apr17.092944@mips.complang.tuwien.ac.at>
In reply to#134926
dxf <dxforth@gmail.com> writes:
>> name filed: 4 byte, 3 first and last char. Only 7 bits,
>>             8th bit counts are flags
...
>Don't know who was first but Fig-forth's variable length names is something
>that Forth Inc and pretty much everyone adopted.  Moore attempted to defend
>'3 chars plus count' but to no avail.  That ship had sailed.

Looking at the traditional length+3 chars and
albert@spenarnc.xs4all.nl's 3 first and last, at least one pair of
words in Forth-94 conflicts on both systems, and WORDS could show them
as REA?????? and REA*E, respectively.  It would be interesting to
determine (say, by checking the words from an existing Forth system),
which scheme produces more conflicts.

Moore continues with this approach in Color Forth, but he uses some
compression approach to usually store more characters in the number of
bits he reserves for the name (IIRC 2 cells, with cell sizes of 20
bits, 18 bits, and 32 bits on different hardware).  I don't remember
if he stores the length.

Another option would be to store a hash value that is computed using
all characters in the name.  If a good hash function is used, the
probability of a conflict is relatively small with, e.g. 4000 names in
a wordlist (about the number of names that Gforth has in the Forth
wordlist), and even the 28 bits that albert@spenarnc.xs4all.nl
provides.  The probability of no conflict is approximately

((2^28-1)/(2^28))^((4000*3999)/2)

i.e.

1 28 lshift s>f fdup 1e f- fswap f/ 4000 dup 1- * 2/ s>f f** f.

The result is 0.97, i.e., there is a 3% probability of conflict for
these numbers.

The disadvantage of this approach is that WORDS or SEE cannot even
show the little about the name that Chuck Moore's approaches or
albert@spenarnc.xs4all.nl's approach shows.  But then, if you are so
pressed for memory that you use one of these approaches, why not also
save the memory for WORDS and SEE?

Another disadvantage is that the system cannot tell if a redefinition
warning comes from a hash conflict or from the name actually being
redefined; but it shares this disadvantage with all approaches that do
not store the full name.

- 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/

[toc] | [prev] | [next] | [standalone]


#134929

Fromalbert@spenarnc.xs4all.nl
Date2026-04-17 12:10 +0200
Message-ID<nnd$3ba8f211$1becf197@8d7cde725037c36d>
In reply to#134928
In article <2026Apr17.092944@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>dxf <dxforth@gmail.com> writes:
>>> name filed: 4 byte, 3 first and last char. Only 7 bits,
>>>             8th bit counts are flags
>...
>>Don't know who was first but Fig-forth's variable length names is something
>>that Forth Inc and pretty much everyone adopted.  Moore attempted to defend
>>'3 chars plus count' but to no avail.  That ship had sailed.
>
>Looking at the traditional length+3 chars and
>albert@spenarnc.xs4all.nl's 3 first and last, at least one pair of
>words in Forth-94 conflicts on both systems, and WORDS could show them
>as REA?????? and REA*E, respectively.  It would be interesting to
>determine (say, by checking the words from an existing Forth system),
>which scheme produces more conflicts.

The argument was that an extreme impractical Forth can be implemented
with this model as guideline, to counter the argument of extreme waste
that I expected.

This is a realistic header in this model.
The name takes 24 bytes or 3 cells, a pointer to an area, a preceding count
and a 1 byte area padded to 8 bytes.


 2513                   #  *********
 2514                   #  *   +   *
 2515                   #  *********
 2516                   #
 2517 21c3 00000000             .balign    8,0x00
 2517      00
 2518                   N_PLUS:                      # Name string
 2519 21c8 01000000             .quad      1         # Name string
 2519      00000000                                  # Name string
 2520 21d0 2B                   .ASCII      "+"      # Name string
 2521 21d1 00000000             .balign    8,0x00    # Name string
 2521      000000
 2522                   PLUS:                        # 0x21D8 is the handle
 2523 21d8 00000000             .quad    X_PLUS          # code
 2523      00000000
 2524 21e0 00000000             .quad    PLUS+HEADSIZE   # data ignored

 2524      00000000
 2525 21e8 00000000             .quad    0x0             # flags, empty
 2525      00000000
 2526 21f0 00000000             .quad    ZLESS           # link pointer
 2526      00000000
 2527 21f8 00000000             .quad    N_PLUS          # points to name
 2527      00000000
 2528 2200 00000000             .quad    0               # source field
 2528      00000000
 2529 2208 00000000             .quad    0               # extra field (spare)
 2529      00000000
 2530
 2531                           X_PLUS:
 2532
 2533 2210 58                   POP     %RAX      #(S1) <- (S1) + (S2)
 2534 2211 5B                   POP     %RBX
 2535 2212 4801D8               ADD     %RAX,%RBX
 2536 2215 50                   PUSH    %RAX
 2537 2216 48AD                 LODSQ                  # NEXT
 2538 2218 FF20                 JMP     QWORD PTR[%RAX]
 2539

<SNIP>

Print the name for +    :
    HEX 21D8  >NFA $@ TYPE

A total of 10 cells for the header alone.
Who cares?

lina+ -a
AMDX86 ciforth beta 2026Apr12
WANT UNUSED
OK
UNUSED .
134221795712  OK


>- anton

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.

[toc] | [prev] | [next] | [standalone]


#134932

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2026-04-18 10:26 +0000
Message-ID<2026Apr18.122611@mips.complang.tuwien.ac.at>
In reply to#134929
albert@spenarnc.xs4all.nl writes:
>The argument was that an extreme impractical Forth can be implemented
>with this model as guideline, to counter the argument of extreme waste
>that I expected.

The users have voted with their feet: They usually have used the
"extremely wasteful" fig-Forth with the default settings (names with
up to 31-char) rather than using the "extremely impractical" option to
only store the first n chars of a name (with n being configurable in
fig-Forth).  "Wastefulness" won over "Impracticality" so convincingly
that even Forth, Inc. switched from "impracticality" to
"wastefulness", as well as almost everyone else.  The exception is
Chuck Moore, who continues with the "impractical" approach in
ColorForth.  Even in the Forth universe, few people seem to use
ColorForth and I have not heard of systems that follow its approach to
names.

Concerning memory consumption, Gforth's development version includes quite a bit of meta-information for two purposes:

1) How the threaded code relates to the source code, not just where
   each definition starts, but also where words are used.

2) How the machine code addresses relate to what is COMPILE,d, to get
proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.

Both sets of informations are in big tables that are stored
out-of-line, not with the headers, and each takes about as much space
as the inline stuff (headers, threaded code, other bodies); the
information where each definition is defined is stored in the headers,
however.  The result is that gforth.fi takes 2.3MB on my system; for
comparison, the inline dictionary stuff is 686464 bytes, the native
code of 465671 bytes for gforth-fast and 892251 for gforth (also
out-of-line, both not in the image).

One may consider this wasteful, but I consider it good use of the RAM
that our machines have; my PC from 1993 had 16MB, the one from 2015
16GB, my current one 64GB.

Concerning header size, here's what we have in Gforth (on a 64-bit system):

here 5 constant five here over - dump 
403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............

I.e., 6 cells for a word with a name that fits in one cell, and one
cell of body.  The cells are:

403AC9C0: Name padded with spaces at the front to align it to a cell boundary
403AC9C8: Name length and flags
403AC9D0: link field (pointer to previous word in the same wordlist)
403AC9D8: header methods (pointer to a method table)
403AC9E0: code field (contains the code address of docon in this case)
403AC9E8: body aka parameter field, contains the value in this case

For more information, read

@InProceedings{paysan&ertl19,
  author =       {Bernd Paysan and M. Anton Ertl},
  title =        {The new {Gforth} Header},
  crossref =     {euroforth19},
  pages =        {5--20},
  url =          {http://www.euroforth.org/ef19/papers/paysan.pdf},
  url-slides =   {http://www.euroforth.org/ef19/papers/paysan-slides.pdf},
  video =        {https://wiki.forth-ev.de/doku.php/events:ef2019:header},
  OPTnote =      {refereed},
  abstract =     {The new Gforth header is designed to directly
                  implement the requirements of Forth-94 and
                  Forth-2012.  Every header is an object with a fixed
                  set of fields (code, parameter, count, name, link)
                  and methods (\texttt{execute}, \texttt{compile,},
                  \texttt{(to)}, \texttt{defer@}, \texttt{does},
                  \texttt{name>interpret}, \texttt{name>compile},
                  \texttt{name>string}, \texttt{name>link}).  The
                  implementation of each method can be changed
                  per-word (prototype-based object-oriented
                  programming).  We demonstrate how to use these
                  features to implement optimization of constants,
                  \texttt{fvalue}, \texttt{defer}, \texttt{immediate},
                  \texttt{to} and other dual-semantics words, and
                  \texttt{synonym}.}
}

@Proceedings{euroforth19,
  title = 	 {35th EuroForth Conference},
  booktitle = 	 {35th EuroForth Conference},
  year = 	 {2019},
  key =		 {EuroForth'19},
  url =          {http://www.euroforth.org/ef19/papers/proceedings.pdf}
}

There have been a few changes since that paper: The body address is
now used as nt and xt, and the "name length and flags" field has
gained another flag or two.

- 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/

[toc] | [prev] | [next] | [standalone]


#134934

Frompeter <peter.noreply@tin.it>
Date2026-04-18 18:11 +0200
Message-ID<20260418181148.000064bb@tin.it>
In reply to#134932
On Sat, 18 Apr 2026 10:26:11 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

> albert@spenarnc.xs4all.nl writes:
> >The argument was that an extreme impractical Forth can be implemented
> >with this model as guideline, to counter the argument of extreme waste
> >that I expected.
> 
> The users have voted with their feet: They usually have used the
> "extremely wasteful" fig-Forth with the default settings (names with
> up to 31-char) rather than using the "extremely impractical" option to
> only store the first n chars of a name (with n being configurable in
> fig-Forth).  "Wastefulness" won over "Impracticality" so convincingly
> that even Forth, Inc. switched from "impracticality" to
> "wastefulness", as well as almost everyone else.  The exception is
> Chuck Moore, who continues with the "impractical" approach in
> ColorForth.  Even in the Forth universe, few people seem to use
> ColorForth and I have not heard of systems that follow its approach to
> names.
> 
> Concerning memory consumption, Gforth's development version includes quite a bit of meta-information for two purposes:
> 
> 1) How the threaded code relates to the source code, not just where
>    each definition starts, but also where words are used.
> 
> 2) How the machine code addresses relate to what is COMPILE,d, to get
> proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.
> 
> Both sets of informations are in big tables that are stored
> out-of-line, not with the headers, and each takes about as much space
> as the inline stuff (headers, threaded code, other bodies); the
> information where each definition is defined is stored in the headers,
> however.  The result is that gforth.fi takes 2.3MB on my system; for
> comparison, the inline dictionary stuff is 686464 bytes, the native
> code of 465671 bytes for gforth-fast and 892251 for gforth (also
> out-of-line, both not in the image).
> 
> One may consider this wasteful, but I consider it good use of the RAM
> that our machines have; my PC from 1993 had 16MB, the one from 2015
> 16GB, my current one 64GB.
> 
> Concerning header size, here's what we have in Gforth (on a 64-bit system):
> 
> here 5 constant five here over - dump 
> 403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
> 403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
> 403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
> 
> I.e., 6 cells for a word with a name that fits in one cell, and one
> cell of body.  The cells are:
> 
> 403AC9C0: Name padded with spaces at the front to align it to a cell boundary
> 403AC9C8: Name length and flags
> 403AC9D0: link field (pointer to previous word in the same wordlist)
> 403AC9D8: header methods (pointer to a method table)
> 403AC9E0: code field (contains the code address of docon in this case)
> 403AC9E8: body aka parameter field, contains the value in this case
> 
I like the idea to have the name at the beginning. I might try that also.
In ntf64/lxf64 I have a compact header! Your example becomes

n' five 16 - 32 dump
0000000071EFF0 08 F0 71 00 30 70 42 00 A8 EF 71 00 03 00 10 00 ..q.0pB...q.....
0000000071F000 A4 46 49 56 45 00 00 00 26 05 25 00 00 00 00 00 .FIVE...&.%.....

71EFF0: xt to token code
71EFF4: xt to native code
71EFF8: link field
71EFFC: lenght of token code
71EFFE: lenght of native code
71F000: flags (3 bits) and count (5 bits)
71F001: name zero extended to 8 byte alignment
71F008: token code 

Compilation is first to token code then this is sent to the native code 
generator
SEE decompiles the token code and SEEA the native code
Code Headers and Data have separate memory regions
A constant have no data associated to it. 
The constant is stored in the code
five in this example is a macro and will be inlined if called from 
another definition.

see five macro
Address   OP                         Instruction
0x71F008  26 05                      LIT1  5
0x71F00A  25                         RET
3 bytes, 2 instructions
ok

seea five
0x427030  48895DF8                    mov       qword [rbp-0x8], rbx
0x427034  48C7C305000000              mov       rbx, 0x5
0x42703B  488D6DF8                    lea       rbp, [rbp-0x8]
0x42703F  C3                          ret
16 bytes, 4 instructions

ticking a word gives a double xt

' five h. $0042´7030´0071´F008

This way I can store an xt and both the token and native code can use it.
It works as I compile the executable to be loaded at 0x400000.


BR
Peter

> For more information, read
> 
> @InProceedings{paysan&ertl19,
>   author =       {Bernd Paysan and M. Anton Ertl},
>   title =        {The new {Gforth} Header},
>   crossref =     {euroforth19},
>   pages =        {5--20},
>   url =          {http://www.euroforth.org/ef19/papers/paysan.pdf},
>   url-slides =   {http://www.euroforth.org/ef19/papers/paysan-slides.pdf},
>   video =        {https://wiki.forth-ev.de/doku.php/events:ef2019:header},
>   OPTnote =      {refereed},
>   abstract =     {The new Gforth header is designed to directly
>                   implement the requirements of Forth-94 and
>                   Forth-2012.  Every header is an object with a fixed
>                   set of fields (code, parameter, count, name, link)
>                   and methods (\texttt{execute}, \texttt{compile,},
>                   \texttt{(to)}, \texttt{defer@}, \texttt{does},
>                   \texttt{name>interpret}, \texttt{name>compile},
>                   \texttt{name>string}, \texttt{name>link}).  The
>                   implementation of each method can be changed
>                   per-word (prototype-based object-oriented
>                   programming).  We demonstrate how to use these
>                   features to implement optimization of constants,
>                   \texttt{fvalue}, \texttt{defer}, \texttt{immediate},
>                   \texttt{to} and other dual-semantics words, and
>                   \texttt{synonym}.}
> }
> 
> @Proceedings{euroforth19,
>   title = 	 {35th EuroForth Conference},
>   booktitle = 	 {35th EuroForth Conference},
>   year = 	 {2019},
>   key =		 {EuroForth'19},
>   url =          {http://www.euroforth.org/ef19/papers/proceedings.pdf}
> }
> 
> There have been a few changes since that paper: The body address is
> now used as nt and xt, and the "name length and flags" field has
> gained another flag or two.
> 
> - anton

[toc] | [prev] | [next] | [standalone]


#134935

Fromalbert@spenarnc.xs4all.nl
Date2026-04-18 20:57 +0200
Message-ID<nnd$3a9d5fc1$6a378fe6@9317bf7a1ac210c1>
In reply to#134932
In article <2026Apr18.122611@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>
>Concerning memory consumption, Gforth's development version includes
>quite a bit of meta-information for two purposes:
>
>1) How the threaded code relates to the source code, not just where
>   each definition starts, but also where words are used.
>
>2) How the machine code addresses relate to what is COMPILE,d, to get
>proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.
>
>Both sets of informations are in big tables that are stored
>out-of-line, not with the headers, and each takes about as much space
>as the inline stuff (headers, threaded code, other bodies); the
>information where each definition is defined is stored in the headers,
>however.  The result is that gforth.fi takes 2.3MB on my system; for
>comparison, the inline dictionary stuff is 686464 bytes, the native
>code of 465671 bytes for gforth-fast and 892251 for gforth (also
>out-of-line, both not in the image).

In view that ctags understands Forth code this seems to be a duplicate
effort.
ctags --lang=forth *.frt
The advantage is that you can use emacs (or other sophisticated
editors) to go to a function in a familiar way that you were used
to in other languages too.
For those not familiar with ctags, in additions to definitions
it finds also references. It also is blindingly fast.
Under 100 mS for hundreds of files.

>
>One may consider this wasteful, but I consider it good use of the RAM
>that our machines have; my PC from 1993 had 16MB, the one from 2015
>16GB, my current one 64GB.
>
>Concerning header size, here's what we have in Gforth (on a 64-bit system):
>
>here 5 constant five here over - dump
>403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
>403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
>403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
>
>I.e., 6 cells for a word with a name that fits in one cell, and one
>cell of body.  The cells are:

This was exactly my point.

>- 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.

[toc] | [prev] | [next] | [standalone]


#134936

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2026-04-19 11:08 +0000
Message-ID<2026Apr19.130826@mips.complang.tuwien.ac.at>
In reply to#134935
albert@spenarnc.xs4all.nl writes:
>In article <2026Apr18.122611@mips.complang.tuwien.ac.at>,
>Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>>
>>Concerning memory consumption, Gforth's development version includes
>>quite a bit of meta-information for two purposes:
>>
>>1) How the threaded code relates to the source code, not just where
>>   each definition starts, but also where words are used.

This is used for making backtraces more informative.

>>2) How the machine code addresses relate to what is COMPILE,d, to get
>>proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.

3) There is also the where table that records where each word is
actually used in the loaded source code, whether there is threaded
code for it or not; it records interpretive use as well as immediate
words where the threaded code is for a different word, if there is
threaded code at all.

>>Both sets of informations are in big tables that are stored
>>out-of-line, not with the headers, and each takes about as much space
>>as the inline stuff (headers, threaded code, other bodies); the
>>information where each definition is defined is stored in the headers,
>>however.  The result is that gforth.fi takes 2.3MB on my system; for
>>comparison, the inline dictionary stuff is 686464 bytes, the native
>>code of 465671 bytes for gforth-fast and 892251 for gforth (also
>>out-of-line, both not in the image).
>
>In view that ctags understands Forth code this seems to be a duplicate
>effort.
>ctags --lang=forth *.frt

I have run ctags and etags with this option on the files from the Gray
directory, and both do not find any of the definitions of TERM (which
exist in calc.fs and oberon.fs); that's probably because they have
been defined with a user-defined defining word.

Due to this shortcoming of etags (and ctags), gforth has included
etags.fs since very early, which really understands Forth code,
because it hooks into the Gforth system and records a tag whenever a
named word is defined.  I dimly remember that we also have done ctags
support (for vi users), but do not find anything about it at the
moment.

>The advantage is that you can use emacs (or other sophisticated
>editors) to go to a function in a familiar way that you were used
>to in other languages too.

For a long time, I thought that etags.fs is sufficient and we do not
need to add LOCATE to Gforth, but once we implemented LOCATE, I found
that I use it much more often than M-. (forth-find-tag).

>For those not familiar with ctags, in additions to definitions
>it finds also references. It also is blindingly fast.
>Under 100 mS for hundreds of files.

So you may be claiming that ctags covers the job of the where table.
I do not see how to achive that.  ctags has an option --cxref, but it
just outputs the definitions in a different format.  E.g., when I say

ctags --lang=forth --cxref *.fs

it shows:

...
disjoint?        187 gray.fs          : disjoint?
empty            105 gray.fs          : empty
...

which shows the definitions of these words, but not the uses.  And it
also does not show the uses of DUP.  By contrast, if I include
gray.fs, and then say WHERE DUP, I get the following:

[... 1128 lines of DUP uses in other files ...]
gray.fs:85:2: dup @ = ;                                                     1128
gray.fs:88:2: dup ! ;                                                       1129
gray.fs:112:2: dup cells/set !                                              1130
gray.fs:120:3: dup @ ,                                                      1131
gray.fs:295:18: source-location dup 2@ swap cr type                         1132
gray.fs:354:2: dup follow-set @ subset? 0=  \ would everything stay the same1133
gray.fs:357:22: follow-set @ union dup follow-set !                         1134
gray.fs:385:2: dup pass2                                                    1135
gray.fs:460:19: operand1 compute dup if                                     1136
gray.fs:499:2: dup operand1 propagate                                       1137

with the DUP use being highlighted.  The where table, which consumes
quite a bit of memory (827_776 bytes in gforth.fi for a 64-bit
system), contains that information.  I do not see anything in the
ctags/etags manual that provides this functionality.  So the LOCATE
information (a cell for each dictionary entry) may be seen as
duplicate information, but the WHERE information does not duplicate
anything.

>>One may consider this wasteful, but I consider it good use of the RAM
>>that our machines have; my PC from 1993 had 16MB, the one from 2015
>>16GB, my current one 64GB.
>>
>>Concerning header size, here's what we have in Gforth (on a 64-bit system):
>>
>>here 5 constant five here over - dump
>>403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
>>403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
>>403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
>>
>>I.e., 6 cells for a word with a name that fits in one cell, and one
>>cell of body.  The cells are:
>
>This was exactly my point.

Your point was that Gforth uses 6 cells for a word with a name that
fits in a cell and where the body takes one cell?

- 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/

[toc] | [prev] | [next] | [standalone]


#134937

Fromalbert@spenarnc.xs4all.nl
Date2026-04-20 13:39 +0200
Message-ID<nnd$64b40630$68764f74@db3e03be9c52e9ce>
In reply to#134936
In article <2026Apr19.130826@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>albert@spenarnc.xs4all.nl writes:
>>In article <2026Apr18.122611@mips.complang.tuwien.ac.at>,
>>Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>>>
>>>Concerning memory consumption, Gforth's development version includes
>>>quite a bit of meta-information for two purposes:
>>>
>>>1) How the threaded code relates to the source code, not just where
>>>   each definition starts, but also where words are used.
>
>This is used for making backtraces more informative.
>
>>>2) How the machine code addresses relate to what is COMPILE,d, to get
>>>proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.
>
>3) There is also the where table that records where each word is
>actually used in the loaded source code, whether there is threaded
>code for it or not; it records interpretive use as well as immediate
>words where the threaded code is for a different word, if there is
>threaded code at all.

There is no argument that the gforth supplies more functionality.

<SNIP>
>I have run ctags and etags with this option on the files from the Gray
>directory, and both do not find any of the definitions of TERM (which
>exist in calc.fs and oberon.fs); that's probably because they have
>been defined with a user-defined defining word.

This is a weak point of ctags. It has not conceived with an extendable
language in mind.

>>editors) to go to a function in a familiar way that you were used
>>to in other languages too.
>
>For a long time, I thought that etags.fs is sufficient and we do not
>need to add LOCATE to Gforth, but once we implemented LOCATE, I found
>that I use it much more often than M-. (forth-find-tag).
>
>>For those not familiar with ctags, in additions to definitions
>>it finds also references. It also is blindingly fast.
>>Under 100 mS for hundreds of files.
>
>So you may be claiming that ctags covers the job of the where table.
>I do not see how to achive that.  ctags has an option --cxref, but it
>just outputs the definitions in a different format.  E.g., when I say

>
<SNIP>
>ctags --lang=forth --cxref *.fs
<SNIP>
>with the DUP use being highlighted.  The where table, which consumes
>quite a bit of memory (827_776 bytes in gforth.fi for a 64-bit
>system), contains that information.  I do not see anything in the
>ctags/etags manual that provides this functionality.  So the LOCATE
>information (a cell for each dictionary entry) may be seen as
>duplicate information, but the WHERE information does not duplicate
>anything.

I rarely use cross references. From my editor the cross reference
of ctags suffice. No argument again that gforth facilities is more
comprehensive.
>
>>>One may consider this wasteful, but I consider it good use of the RAM
>>>that our machines have; my PC from 1993 had 16MB, the one from 2015
>>>16GB, my current one 64GB.
>>>
>>>Concerning header size, here's what we have in Gforth (on a 64-bit system):
>>>
>>>here 5 constant five here over - dump
>>>403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
>>>403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
>>>403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
>>>
>>>I.e., 6 cells for a word with a name that fits in one cell, and one
>>>cell of body.  The cells are:
>>
>>This was exactly my point.
>
>Your point was that Gforth uses 6 cells for a word with a name that
>fits in a cell and where the body takes one cell?

The point was that in this time and age you don't try to save a
few cells here and there.

The bottom line is, in view of the superior cross reference is
that an argument to trade mpeforth for gforth. Or can we make
do with the weaker ctags (or dispense with such a facility.)

>
>- 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.

[toc] | [prev] | [next] | [standalone]


#135087

Frompeter <peter.noreply@tin.it>
Date2026-05-21 10:28 +0200
Message-ID<20260521102817.0000237b@tin.it>
In reply to#134932
On Sat, 18 Apr 2026 10:26:11 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

> albert@spenarnc.xs4all.nl writes:
> >The argument was that an extreme impractical Forth can be implemented
> >with this model as guideline, to counter the argument of extreme waste
> >that I expected.
> 
> The users have voted with their feet: They usually have used the
> "extremely wasteful" fig-Forth with the default settings (names with
> up to 31-char) rather than using the "extremely impractical" option to
> only store the first n chars of a name (with n being configurable in
> fig-Forth).  "Wastefulness" won over "Impracticality" so convincingly
> that even Forth, Inc. switched from "impracticality" to
> "wastefulness", as well as almost everyone else.  The exception is
> Chuck Moore, who continues with the "impractical" approach in
> ColorForth.  Even in the Forth universe, few people seem to use
> ColorForth and I have not heard of systems that follow its approach to
> names.
> 
> Concerning memory consumption, Gforth's development version includes quite a bit of meta-information for two purposes:
> 
> 1) How the threaded code relates to the source code, not just where
>    each definition starts, but also where words are used.
> 
> 2) How the machine code addresses relate to what is COMPILE,d, to get
> proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.
> 
> Both sets of informations are in big tables that are stored
> out-of-line, not with the headers, and each takes about as much space
> as the inline stuff (headers, threaded code, other bodies); the
> information where each definition is defined is stored in the headers,
> however.  The result is that gforth.fi takes 2.3MB on my system; for
> comparison, the inline dictionary stuff is 686464 bytes, the native
> code of 465671 bytes for gforth-fast and 892251 for gforth (also
> out-of-line, both not in the image).
> 
> One may consider this wasteful, but I consider it good use of the RAM
> that our machines have; my PC from 1993 had 16MB, the one from 2015
> 16GB, my current one 64GB.
> 
> Concerning header size, here's what we have in Gforth (on a 64-bit system):
> 
> here 5 constant five here over - dump 
> 403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
> 403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
> 403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
> 
> I.e., 6 cells for a word with a name that fits in one cell, and one
> cell of body.  The cells are:
> 
> 403AC9C0: Name padded with spaces at the front to align it to a cell boundary
> 403AC9C8: Name length and flags
> 403AC9D0: link field (pointer to previous word in the same wordlist)
> 403AC9D8: header methods (pointer to a method table)
> 403AC9E0: code field (contains the code address of docon in this case)
> 403AC9E8: body aka parameter field, contains the value in this case
> 
> For more information, read
> 


I did go ahead and change the LXF64 header to something more like the 
gforth one! This is what it looks like:

\ offset length purpose
\ -24-8n 8+8n   counted name aligned and patched with zeros n=0,1,2,3 
\ -16   8       xt (xt token + xt native)
\ -8    4       link
\ -4    2       Tlen Token code length
\ -2    2       Nlen Native code length
\  0    1       flag byte               <- NT points here
\  1    1       offset to name from NT
\  2    2       unused
\  4    4       pointer to translate-name
\  8    Tlen    token code   

Your example of five becomes

align-h here-h 5 constant five here-h over - dump
000000007227A0 04 46 49 56 45 00 00 00 C0 27 72 00 30 68 42 00 .FIVE....'r.0hB.
000000007227B0 F8 D0 71 00 03 00 10 00 20 18 00 00 50 00 A0 00 ..q..... ...P...
000000007227C0 26 05 25 00 00 00 00 00 00 00 00 00 00 00 00 00 &.%.............

I have the counted name aligned and zero padded at the start.
This will allow to compare 8 bytes at a time

: NCOMP  ( addr  addr'  - f) \ compare counted name strings strings 0= match     
    dup c@ 1+ 
        0 ?do 
        over i + @ over i + @ 
        <> if 2drop unloop true exit then
        8 +loop 2drop false ;

I have checked forth-wordlist and 71.5% of all words will require only one
comparison. 1.5% will require more then 2 comparisons.

The other interesting change I did was to put in a link to translate-name.
Each word now knows how to interpret, compile and postpone itself!

I have now 3 standard word types
translate-name
translate-name-immediate
translate-name-macro

This takes away all checks of the flag and following conditionals.
I could actually remove the flag byte.

I also introduced SET-TRANSLATOR that sets the translator of the 
last defined word. This lets me define all state smart words 
without state! S" illustrates this:

: [S"]
    34 parse slit ; immediate

' ht-execute    
:noname drop postpone [S"] ;
:noname drop [n'] [S"] lit, postpone ht-execute  ;
create translate-s"
, , ,

: S"
    34 parse dup >r pocket dup >r swap  move  r> r> ;
 
translate-s" set-translator

ht-execute executes the NT. [n'] returns the NT

C", TO, ACTION-OF, IS and S\" are implemented in similar ways.

Now the recognizers are starting to make good sense!

BR
Peter



> @InProceedings{paysan&ertl19,
>   author =       {Bernd Paysan and M. Anton Ertl},
>   title =        {The new {Gforth} Header},
>   crossref =     {euroforth19},
>   pages =        {5--20},
>   url =          {http://www.euroforth.org/ef19/papers/paysan.pdf},
>   url-slides =   {http://www.euroforth.org/ef19/papers/paysan-slides.pdf},
>   video =        {https://wiki.forth-ev.de/doku.php/events:ef2019:header},
>   OPTnote =      {refereed},
>   abstract =     {The new Gforth header is designed to directly
>                   implement the requirements of Forth-94 and
>                   Forth-2012.  Every header is an object with a fixed
>                   set of fields (code, parameter, count, name, link)
>                   and methods (\texttt{execute}, \texttt{compile,},
>                   \texttt{(to)}, \texttt{defer@}, \texttt{does},
>                   \texttt{name>interpret}, \texttt{name>compile},
>                   \texttt{name>string}, \texttt{name>link}).  The
>                   implementation of each method can be changed
>                   per-word (prototype-based object-oriented
>                   programming).  We demonstrate how to use these
>                   features to implement optimization of constants,
>                   \texttt{fvalue}, \texttt{defer}, \texttt{immediate},
>                   \texttt{to} and other dual-semantics words, and
>                   \texttt{synonym}.}
> }
> 
> @Proceedings{euroforth19,
>   title = 	 {35th EuroForth Conference},
>   booktitle = 	 {35th EuroForth Conference},
>   year = 	 {2019},
>   key =		 {EuroForth'19},
>   url =          {http://www.euroforth.org/ef19/papers/proceedings.pdf}
> }
> 
> There have been a few changes since that paper: The body address is
> now used as nt and xt, and the "name length and flags" field has
> gained another flag or two.
> 
> - anton

[toc] | [prev] | [next] | [standalone]


#135090

Fromminforth <minforth@gmx.net>
Date2026-05-22 12:04 +0200
Message-ID<n7ao0gF5mqgU1@mid.individual.net>
In reply to#135087
Am 21.05.2026 um 10:28 schrieb peter:
> On Sat, 18 Apr 2026 10:26:11 GMT
> anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
> 
>> albert@spenarnc.xs4all.nl writes:
>>> The argument was that an extreme impractical Forth can be implemented
>>> with this model as guideline, to counter the argument of extreme waste
>>> that I expected.
>>
>> The users have voted with their feet: They usually have used the
>> "extremely wasteful" fig-Forth with the default settings (names with
>> up to 31-char) rather than using the "extremely impractical" option to
>> only store the first n chars of a name (with n being configurable in
>> fig-Forth).  "Wastefulness" won over "Impracticality" so convincingly
>> that even Forth, Inc. switched from "impracticality" to
>> "wastefulness", as well as almost everyone else.  The exception is
>> Chuck Moore, who continues with the "impractical" approach in
>> ColorForth.  Even in the Forth universe, few people seem to use
>> ColorForth and I have not heard of systems that follow its approach to
>> names.
>>
>> Concerning memory consumption, Gforth's development version includes quite a bit of meta-information for two purposes:
>>
>> 1) How the threaded code relates to the source code, not just where
>>     each definition starts, but also where words are used.
>>
>> 2) How the machine code addresses relate to what is COMPILE,d, to get
>> proper decompilation with SEE-CODE, SIMPLE-SEE, and SEE.
>>
>> Both sets of informations are in big tables that are stored
>> out-of-line, not with the headers, and each takes about as much space
>> as the inline stuff (headers, threaded code, other bodies); the
>> information where each definition is defined is stored in the headers,
>> however.  The result is that gforth.fi takes 2.3MB on my system; for
>> comparison, the inline dictionary stuff is 686464 bytes, the native
>> code of 465671 bytes for gforth-fast and 892251 for gforth (also
>> out-of-line, both not in the image).
>>
>> One may consider this wasteful, but I consider it good use of the RAM
>> that our machines have; my PC from 1993 had 16MB, the one from 2015
>> 16GB, my current one 64GB.
>>
>> Concerning header size, here's what we have in Gforth (on a 64-bit system):
>>
>> here 5 constant five here over - dump
>> 403AC9C0: 20 20 20 20  66 69 76 65 - 04 00 00 00  00 00 00 00      five........
>> 403AC9D0: 08 C7 3A 40  00 00 00 00 - 81 EA A1 9D  EA 55 00 00  ..:@.........U..
>> 403AC9E0: 60 AF 30 40  00 00 00 00 - 05 00 00 00  00 00 00 00  `.0@............
>>
>> I.e., 6 cells for a word with a name that fits in one cell, and one
>> cell of body.  The cells are:
>>
>> 403AC9C0: Name padded with spaces at the front to align it to a cell boundary
>> 403AC9C8: Name length and flags
>> 403AC9D0: link field (pointer to previous word in the same wordlist)
>> 403AC9D8: header methods (pointer to a method table)
>> 403AC9E0: code field (contains the code address of docon in this case)
>> 403AC9E8: body aka parameter field, contains the value in this case
>>
>> For more information, read
>>
> 
> 
> I did go ahead and change the LXF64 header to something more like the
> gforth one! This is what it looks like:
> 
> \ offset length purpose
> \ -24-8n 8+8n   counted name aligned and patched with zeros n=0,1,2,3
> \ -16   8       xt (xt token + xt native)
> \ -8    4       link
> \ -4    2       Tlen Token code length
> \ -2    2       Nlen Native code length
> \  0    1       flag byte               <- NT points here
> \  1    1       offset to name from NT
> \  2    2       unused
> \  4    4       pointer to translate-name
> \  8    Tlen    token code
> 
> Your example of five becomes
> 
> align-h here-h 5 constant five here-h over - dump
> 000000007227A0 04 46 49 56 45 00 00 00 C0 27 72 00 30 68 42 00 .FIVE....'r.0hB.
> 000000007227B0 F8 D0 71 00 03 00 10 00 20 18 00 00 50 00 A0 00 ..q..... ...P...
> 000000007227C0 26 05 25 00 00 00 00 00 00 00 00 00 00 00 00 00 &.%.............
> 
> I have the counted name aligned and zero padded at the start.
> This will allow to compare 8 bytes at a time
> 
> : NCOMP  ( addr  addr'  - f) \ compare counted name strings strings 0= match
>      dup c@ 1+
>          0 ?do
>          over i + @ over i + @
>          <> if 2drop unloop true exit then
>          8 +loop 2drop false ;
> 
> I have checked forth-wordlist and 71.5% of all words will require only one
> comparison. 1.5% will require more then 2 comparisons.
> 
> The other interesting change I did was to put in a link to translate-name.
> Each word now knows how to interpret, compile and postpone itself!
> 
> I have now 3 standard word types
> translate-name
> translate-name-immediate
> translate-name-macro
> 
> This takes away all checks of the flag and following conditionals.
> I could actually remove the flag byte.
> 
> I also introduced SET-TRANSLATOR that sets the translator of the
> last defined word. This lets me define all state smart words
> without state! S" illustrates this:
> 
> : [S"]
>      34 parse slit ; immediate
> 
> ' ht-execute
> :noname drop postpone [S"] ;
> :noname drop [n'] [S"] lit, postpone ht-execute  ;
> create translate-s"
> , , ,
> 
> : S"
>      34 parse dup >r pocket dup >r swap  move  r> r> ;
>   
> translate-s" set-translator
> 
> ht-execute executes the NT. [n'] returns the NT
> 
> C", TO, ACTION-OF, IS and S\" are implemented in similar ways.
> 
> Now the recognizers are starting to make good sense!

My approach from a different angle: minimize header size AND have
dual execution tokens for STATE-independent definitions

Header struct:  <name> (lfa,nfa,ccfa,cfa)
<name> name string
lfa   link field address to preceding header
nfa   pointer to <name>
ccfa  compile-time code field address
cfa   execution-time code field address

Different word types are recognised by comparing cfa with ccfa:
ccfa empty: "normal" word
cfa empty: compile-only word
cfa=ccfa: immediate word

[toc] | [prev] | [next] | [standalone]


#135091

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2026-05-23 18:12 +0000
Message-ID<2026May23.201220@mips.complang.tuwien.ac.at>
In reply to#135087
peter <peter.noreply@tin.it> writes:
>I did go ahead and change the LXF64 header to something more like the 
>gforth one! This is what it looks like:
>
>\ offset length purpose
>\ -24-8n 8+8n   counted name aligned and patched with zeros n=0,1,2,3 
>\ -16   8       xt (xt token + xt native)
>\ -8    4       link
>\ -4    2       Tlen Token code length
>\ -2    2       Nlen Native code length
>\  0    1       flag byte               <- NT points here
>\  1    1       offset to name from NT
>\  2    2       unused
>\  4    4       pointer to translate-name
>\  8    Tlen    token code   
...
>The other interesting change I did was to put in a link to translate-name.
>Each word now knows how to interpret, compile and postpone itself!
>
>I have now 3 standard word types
>translate-name
>translate-name-immediate
>translate-name-macro
>
>This takes away all checks of the flag and following conditionals.
>I could actually remove the flag byte.

In Gforth we did this by making the implementations of NAME>INTERPRET
and NAME>COMPILE word-specific:

Words with default compilation semantics have DEFAULT-NAME>COMP als
implementation, immediate words have IMM>COMP as implementation, and
other words (e.g., S") have other implementations.

\ the actual implementation is a bit different, but this is the
\ easier-to-understand version.
: default-name>comp ( nt -- xt1 xt2 )
  name>interpret ['] compile, ;

: imm>comp ( nt -- xt1 xt2 )
  name>interpret ['] execute ;

In Gforth translate-name does not differentiate between different
kinds of words; it always produces "nt translate-name" on success, and
NAME>COMPILE takes care of the differences.  My guess us that you do
it differently because you do not have NAME>COMPILE.  Am I corrent?

>I also introduced SET-TRANSLATOR that sets the translator of the 
>last defined word. This lets me define all state smart words 
>without state! S" illustrates this:
>
>: [S"]
>    34 parse slit ; immediate
>
>' ht-execute    
>:noname drop postpone [S"] ;
>:noname drop [n'] [S"] lit, postpone ht-execute  ;
>create translate-s"
>, , ,
>
>: S"
>    34 parse dup >r pocket dup >r swap  move  r> r> ;
> 
>translate-s" set-translator

Interesting.

>ht-execute executes the NT. [n'] returns the NT

So you have NTs.  Do you have NT>COMPILE?  If so, the differences
between default and immediate and other words should already be
implemented there.

- 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/

[toc] | [prev] | [next] | [standalone]


#135092

Frompeter <peter.noreply@tin.it>
Date2026-05-23 23:09 +0200
Message-ID<20260523230609.0000568a@tin.it>
In reply to#135091
On Sat, 23 May 2026 18:12:20 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

> peter <peter.noreply@tin.it> writes:
> >I did go ahead and change the LXF64 header to something more like the 
> >gforth one! This is what it looks like:
> >
> >\ offset length purpose
> >\ -24-8n 8+8n   counted name aligned and patched with zeros n=0,1,2,3 
> >\ -16   8       xt (xt token + xt native)
> >\ -8    4       link
> >\ -4    2       Tlen Token code length
> >\ -2    2       Nlen Native code length
> >\  0    1       flag byte               <- NT points here
> >\  1    1       offset to name from NT
> >\  2    2       unused
> >\  4    4       pointer to translate-name
> >\  8    Tlen    token code   
> ...
> >The other interesting change I did was to put in a link to translate-name.
> >Each word now knows how to interpret, compile and postpone itself!
> >
> >I have now 3 standard word types
> >translate-name
> >translate-name-immediate
> >translate-name-macro
> >
> >This takes away all checks of the flag and following conditionals.
> >I could actually remove the flag byte.
> 
> In Gforth we did this by making the implementations of NAME>INTERPRET
> and NAME>COMPILE word-specific:
> 
> Words with default compilation semantics have DEFAULT-NAME>COMP als
> implementation, immediate words have IMM>COMP as implementation, and
> other words (e.g., S") have other implementations.
> 
> \ the actual implementation is a bit different, but this is the
> \ easier-to-understand version.
> : default-name>comp ( nt -- xt1 xt2 )
>   name>interpret ['] compile, ;
> 
> : imm>comp ( nt -- xt1 xt2 )
>   name>interpret ['] execute ;

I studied your linked document and slides a understood it worked 
something like that. Seeing your VT table gave me the idea to
put in a link to the translate record

> 
> In Gforth translate-name does not differentiate between different
> kinds of words; it always produces "nt translate-name" on success, and
> NAME>COMPILE takes care of the differences.  My guess us that you do
> it differently because you do not have NAME>COMPILE.  Am I corrent?

No I have also name>compile, but it is not used anymore

> 
> >I also introduced SET-TRANSLATOR that sets the translator of the 
> >last defined word. This lets me define all state smart words 
> >without state! S" illustrates this:
> >
> >: [S"]
> >    34 parse slit ; immediate
> >
> >' ht-execute    
> >:noname drop postpone [S"] ;
> >:noname drop [n'] [S"] lit, postpone ht-execute  ;
> >create translate-s"
> >, , ,
> >
> >: S"
> >    34 parse dup >r pocket dup >r swap  move  r> r> ;
> > 
> >translate-s" set-translator
> 
> Interesting.
> 
> >ht-execute executes the NT. [n'] returns the NT
> 
> So you have NTs.  Do you have NT>COMPILE?  If so, the differences
> between default and immediate and other words should already be
> implemented there.

HT stands for header token. I started using that long before the NT
was introduced. They are of course the same.

name>compile was defined as:

: NAME>COMPILE   ( nt -- w xt )
    dup nt>flag c@ 64 and if ['] ht-execute else ['] ht-compile, then ;

Now it is

: NAME>COMPILE   ( nt -- w xt )
    dup nt>trans l@ cell+ @ ;

ht-compile, is defined as

: HT-COMPILE, ( ht -- )
	dup nt>flag c@ 32 and 
    if  ht-expand-macro exit then
	ht-,call ;	

If the word is a macro it is expanded otherwise an ordinary 
call is compiled.
About 50% of all words are macros.

With the 3 translate-name-xxx all the flag testing is gone!
The right execution path is set at creation time.

The ability to set a specific translation record for the 
state smart words comes as an extra benefit.

BR
Peter

> - anton

[toc] | [prev] | [next] | [standalone]


#135093

Frompeter <peter.noreply@tin.it>
Date2026-05-24 10:07 +0200
Message-ID<20260524100709.00004b1d@tin.it>
In reply to#135091
On Sat, 23 May 2026 18:12:20 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

> peter <peter.noreply@tin.it> writes:
> >I did go ahead and change the LXF64 header to something more like the 
> >gforth one! This is what it looks like:
> >
> >\ offset length purpose
> >\ -24-8n 8+8n   counted name aligned and patched with zeros n=0,1,2,3 
> >\ -16   8       xt (xt token + xt native)
> >\ -8    4       link
> >\ -4    2       Tlen Token code length
> >\ -2    2       Nlen Native code length
> >\  0    1       flag byte               <- NT points here
> >\  1    1       offset to name from NT
> >\  2    2       unused
> >\  4    4       pointer to translate-name
> >\  8    Tlen    token code   
> ...
> >The other interesting change I did was to put in a link to translate-name.
> >Each word now knows how to interpret, compile and postpone itself!
> >
> >I have now 3 standard word types
> >translate-name
> >translate-name-immediate
> >translate-name-macro
> >
> >This takes away all checks of the flag and following conditionals.
> >I could actually remove the flag byte.
> 
> In Gforth we did this by making the implementations of NAME>INTERPRET
> and NAME>COMPILE word-specific:
> 
> Words with default compilation semantics have DEFAULT-NAME>COMP als
> implementation, immediate words have IMM>COMP as implementation, and
> other words (e.g., S") have other implementations.
> 
> \ the actual implementation is a bit different, but this is the
> \ easier-to-understand version.
> : default-name>comp ( nt -- xt1 xt2 )
>   name>interpret ['] compile, ;
> 
> : imm>comp ( nt -- xt1 xt2 )
>   name>interpret ['] execute ;

I studied your linked document and slides a understood it worked 
something like that. Seeing your VT table gave me the idea to
put in a link to the translate record

> 
> In Gforth translate-name does not differentiate between different
> kinds of words; it always produces "nt translate-name" on success, and
> NAME>COMPILE takes care of the differences.  My guess us that you do
> it differently because you do not have NAME>COMPILE.  Am I corrent?

No I have also name>compile, but it is not used anymore

> 
> >I also introduced SET-TRANSLATOR that sets the translator of the 
> >last defined word. This lets me define all state smart words 
> >without state! S" illustrates this:
> >
> >: [S"]
> >    34 parse slit ; immediate
> >
> >' ht-execute    
> >:noname drop postpone [S"] ;
> >:noname drop [n'] [S"] lit, postpone ht-execute  ;
> >create translate-s"
> >, , ,
> >
> >: S"
> >    34 parse dup >r pocket dup >r swap  move  r> r> ;
> > 
> >translate-s" set-translator
> 
> Interesting.
> 
> >ht-execute executes the NT. [n'] returns the NT
> 
> So you have NTs.  Do you have NT>COMPILE?  If so, the differences
> between default and immediate and other words should already be
> implemented there.

HT stands for header token. I started using that long before the NT
was introduced. They are of course the same.

name>compile was defined as:

: NAME>COMPILE   ( nt -- w xt )
    dup nt>flag c@ 64 and if ['] ht-execute else ['] ht-compile, then ;

Now it is

: NAME>COMPILE   ( nt -- w xt )
    dup nt>trans l@ cell+ @ ;

ht-compile, is defined as

: HT-COMPILE, ( ht -- )
	dup nt>flag c@ 32 and 
    if  ht-expand-macro exit then
	ht-,call ;	

If the word is a macro it is expanded otherwise an ordinary 
call is compiled.
About 50% of all words are macros.

With the 3 translate-name-xxx all the flag testing is gone!
The right execution path is set at creation time.

The ability to set a specific translation record for the 
state smart words comes as an extra benefit.

To really integrate the recognizers well I made REC-NAME the
primary name finding function. Fnd-name is then defined as:

: FIND-NAME ( caddr u -- ht | 0)
	rec-name dup if drop then ;

Translate-none returns a null pointer in my system.

BR
Peter

> - anton

[toc] | [prev] | [next] | [standalone]


#135096

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2026-05-25 13:34 +0000
Message-ID<2026May25.153448@mips.complang.tuwien.ac.at>
In reply to#135093
peter <peter.noreply@tin.it> writes:
>On Sat, 23 May 2026 18:12:20 GMT
>anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
>> peter <peter.noreply@tin.it> writes:
>> >The other interesting change I did was to put in a link to translate-name.
>> >Each word now knows how to interpret, compile and postpone itself!
>> >
>> >I have now 3 standard word types
>> >translate-name
>> >translate-name-immediate
>> >translate-name-macro
>> >
>> >This takes away all checks of the flag and following conditionals.
>> >I could actually remove the flag byte.
>> 
>> In Gforth we did this by making the implementations of NAME>INTERPRET
>> and NAME>COMPILE word-specific:
>> 
>> Words with default compilation semantics have DEFAULT-NAME>COMP als
>> implementation, immediate words have IMM>COMP as implementation, and
>> other words (e.g., S") have other implementations.
>> 
>> \ the actual implementation is a bit different, but this is the
>> \ easier-to-understand version.
>> : default-name>comp ( nt -- xt1 xt2 )
>>   name>interpret ['] compile, ;
>> 
>> : imm>comp ( nt -- xt1 xt2 )
>>   name>interpret ['] execute ;
>
>I studied your linked document and slides a understood it worked 
>something like that. Seeing your VT table gave me the idea to
>put in a link to the translate record

Nowadays we call the table HM, for header methods.  VT is too generic.
In development Gforth, you can see the header methods for a word by
using .HM on its NT.  E.g.:

``+ .hm 
opt:     $7FA3C4A363D8 
to:      n/a 
extra:   $0 
>int:    default-name>int 
>comp:   default-name>comp 
>string: named>string 
>link:   named>link

>: NAME>COMPILE   ( nt -- w xt )
>    dup nt>trans l@ cell+ @ ;

That's interesting.  Instead of defining TRANSLATE-NAME's compilation
action in terms of NAME>COMPILE, you put the differences between
different names into TRANSLATE-NAME, and implement NAME>COMPILE by
accessing the internals of TRANSLATE-NAME.

>With the 3 translate-name-xxx all the flag testing is gone!

Yes, we also eliminated nearly all flags with the new header format.
We kept a compile-only flag (for warning about compile-only words),
and added an obsolete flag (for warning about words that are going to
be removed from a future Gforth), because warnings do not introduce
complicated control flow.

>The ability to set a specific translation record for the 
>state smart words comes as an extra benefit.

I guess you mean words with non-immediate non-default compilation
semantics, and yes, being able to tell the Forth system how it should
treat such a word at text interpretation time avoids the unpleasant
surprises that STATE-smart immediate words (that try to figure out at
run-time by inspecting STATE what they should do, but the STATE at
run-time does not provide information about whether their
interpretation semantics or compilation semantics is performed).

>>To really integrate the recognizers well I made REC-NAME the
>primary name finding function. Fnd-name is then defined as:
>
>: FIND-NAME ( caddr u -- ht | 0)
>	rec-name dup if drop then ;
>
>Translate-none returns a null pointer in my system.

Yes, we have written about the idea of unifying recognizers and
wordlists [paysan20].  Development Gforth implements this idea.  E.g.,
if you do

s" dup" forth-wordlist execute

you find a translation on the stack, consisting of the nt of DUP and
of TRANSLATE-NAME.  The implementations of FIND-NAME-IN and FIND-NAME
are:

: find-name-in  ( c-addr u wid -- nt | 0 ) \ gforth
    execute translate-none = IF  0  THEN ;

: find-name ( c-addr u -- nt | 0 ) \ gforth
    ['] rec-name find-name-in ;

The latter makes use of the fact that the recognizer sequence in
REC-NAME can be treated as wordlist.  That relies on the fact that
only wordlists are in the search order (and the search-order is in the
deferred word REC-NAME).  If you put, e.g., REC-NUMBER into the search
order, the result will be that FIND-NAME will push a single-cell or
double-cell number when you pass it something that is recognized by
that REC-NUMBER.  But that's the usual fare in Forth, if you hold it
wrong, it produces the wrong result.

The current proposal proposes the nested recognizers, but does not
require wordlists to work as recognizers.

@InProceedings{paysan20,
  author =       {Bernd Paysan and M. Anton Ertl},
  title =        {The Grand Recognizer Unification},
  crossref =     {euroforth20},
  pages =        {19--22},
  url =          {http://www.euroforth.org/ef20/papers/paysan.pdf},
  url-slides =   {http://www.euroforth.org/ef20/papers/paysan-slides.pdf},
  video =        {https://www.youtube.com/watch?v=VUi6uYqIbTI},
  OPTnote =      {not refereed},
  abstract =     {There is an obvious similarity between the search
                  order and a recognizer sequence, which has led to
                  similarities in proposed words (e.g.,
                  \code{get-recognizer} is modeled on
                  \code{get-order}).  By turning word lists into
                  recognizers, we unify these concepts.  We also turn
                  recognizer sequences (and be extension the search
                  order) into a recognizer, which allows nestable
                  recognizer sequences and wordlist sequences in the
                  search order.  The implementation becomes simpler,
                  too.}
}
@Proceedings{euroforth20,
  title = 	 {36th EuroForth Conference},
  booktitle = 	 {36th EuroForth Conference},
  year = 	 {2020},
  key =		 {EuroForth'20},
  url =          {http://www.euroforth.org/ef20/papers/proceedings.pdf}
}

- 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/

[toc] | [prev] | [next] | [standalone]


#135102

Frompeter <peter.noreply@tin.it>
Date2026-05-27 10:42 +0200
Message-ID<20260527104243.00001ca0@tin.it>
In reply to#135096
On Mon, 25 May 2026 13:34:48 GMT
anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:

> peter <peter.noreply@tin.it> writes:
> >On Sat, 23 May 2026 18:12:20 GMT
> >anton@mips.complang.tuwien.ac.at (Anton Ertl) wrote:
> >> peter <peter.noreply@tin.it> writes:
> >> >The other interesting change I did was to put in a link to translate-name.
> >> >Each word now knows how to interpret, compile and postpone itself!
> >> >
> >> >I have now 3 standard word types
> >> >translate-name
> >> >translate-name-immediate
> >> >translate-name-macro
> >> >
> >> >This takes away all checks of the flag and following conditionals.
> >> >I could actually remove the flag byte.
> >> 
> >> In Gforth we did this by making the implementations of NAME>INTERPRET
> >> and NAME>COMPILE word-specific:
> >> 
> >> Words with default compilation semantics have DEFAULT-NAME>COMP als
> >> implementation, immediate words have IMM>COMP as implementation, and
> >> other words (e.g., S") have other implementations.
> >> 
> >> \ the actual implementation is a bit different, but this is the
> >> \ easier-to-understand version.
> >> : default-name>comp ( nt -- xt1 xt2 )
> >>   name>interpret ['] compile, ;
> >> 
> >> : imm>comp ( nt -- xt1 xt2 )
> >>   name>interpret ['] execute ;
> >
> >I studied your linked document and slides a understood it worked 
> >something like that. Seeing your VT table gave me the idea to
> >put in a link to the translate record
> 
> Nowadays we call the table HM, for header methods.  VT is too generic.
> In development Gforth, you can see the header methods for a word by
> using .HM on its NT.  E.g.:
> 
> ``+ .hm 
> opt:     $7FA3C4A363D8 
> to:      n/a 
> extra:   $0 
> >int:    default-name>int 
> >comp:   default-name>comp 
> >string: named>string 
> >link:   named>link
> 
> >: NAME>COMPILE   ( nt -- w xt )
> >    dup nt>trans l@ cell+ @ ;
> 
> That's interesting.  Instead of defining TRANSLATE-NAME's compilation
> action in terms of NAME>COMPILE, you put the differences between
> different names into TRANSLATE-NAME, and implement NAME>COMPILE by
> accessing the internals of TRANSLATE-NAME.
> 
> >With the 3 translate-name-xxx all the flag testing is gone!
> 
> Yes, we also eliminated nearly all flags with the new header format.
> We kept a compile-only flag (for warning about compile-only words),
> and added an obsolete flag (for warning about words that are going to
> be removed from a future Gforth), because warnings do not introduce
> complicated control flow.
> 
> >The ability to set a specific translation record for the 
> >state smart words comes as an extra benefit.
> 
> I guess you mean words with non-immediate non-default compilation
> semantics, and yes, being able to tell the Forth system how it should
> treat such a word at text interpretation time avoids the unpleasant
> surprises that STATE-smart immediate words (that try to figure out at
> run-time by inspecting STATE what they should do, but the STATE at
> run-time does not provide information about whether their
> interpretation semantics or compilation semantics is performed).
> 
> >>To really integrate the recognizers well I made REC-NAME the
> >primary name finding function. Fnd-name is then defined as:
> >
> >: FIND-NAME ( caddr u -- ht | 0)
> >	rec-name dup if drop then ;
> >
> >Translate-none returns a null pointer in my system.
> 
> Yes, we have written about the idea of unifying recognizers and
> wordlists [paysan20].  Development Gforth implements this idea.  E.g.,
> if you do
> 
> s" dup" forth-wordlist execute
> 
> you find a translation on the stack, consisting of the nt of DUP and
> of TRANSLATE-NAME.  The implementations of FIND-NAME-IN and FIND-NAME
> are:
> 
> : find-name-in  ( c-addr u wid -- nt | 0 ) \ gforth
>     execute translate-none = IF  0  THEN ;
> 
> : find-name ( c-addr u -- nt | 0 ) \ gforth
>     ['] rec-name find-name-in ;
> 
> The latter makes use of the fact that the recognizer sequence in
> REC-NAME can be treated as wordlist.  That relies on the fact that
> only wordlists are in the search order (and the search-order is in the
> deferred word REC-NAME).  If you put, e.g., REC-NUMBER into the search
> order, the result will be that FIND-NAME will push a single-cell or
> double-cell number when you pass it something that is recognized by
> that REC-NUMBER.  But that's the usual fare in Forth, if you hold it
> wrong, it produces the wrong result.
 
My first reaction when the idea of recognizers were presented was that
they should be combined with word-lists and search order. I have never
followed up on that idea. Interesting that you are doing it.

Instead in the latest version rec-name has been slim lined to avoid
unnecessary work. In LXF64 I store the names in uppercase. At find time
the parsed string also needs to be upper cased and a hash calculated.
I now do this one time and use the result for all comparisons in the 
different word-lists rec-name is defined as

: REC-NAME  ( c-addr n --  0| ht translator )
    dup 0= if nip exit then                 \ empty string
    #order @ 0= if 2drop 0 exit then        \ empty order
    copy-upcase-hash                        \ hash  namestring in namebuf
	#order @    
	
	begin
		dup
	while
		1- >r
		dup                         \ hash hash R:ordernr
		r@ cells context + @ swap   \ hash wid hash
        hash>bucket @ namebuf swap          \ hash name bucket
        search-bucket2                      \ hash nt|0
		dup
		if r>drop nip dup nt>trans l@ exit then      
		drop r>
	repeat 
    nip ;

copy-upcase-hash takes care of the work in just one loop and places 
the string in namebuf. Earlier it was 3 passes over the string!

hash>bucket calculates the bucket to search from the hash and wid.
Wordlists can have different number of buckets

This saved 2-3 ms in recompiling the whole Forth system!
Hardly measurable but still a 5% improvement!

> The current proposal proposes the nested recognizers, but does not
> require wordlists to work as recognizers.

I checked the text and slides but did not like everything that was 
presented. I then downloaded a fresh tarball from gforth.org and
followed the instructions to install it on a debian WSL instance. 
It was not a good idea! running install-deps installed 150 packages
totaling 640 MB! Looked like mostly graphics stuff. I run only slim
console only installations of Linux!

I think it should have warned me before starting the installation!

Despite I saw install-deps compile swig with forth support configure 
did not find the freshly compiled copy and swig support was not avalible

The gforth binary runs just fine and I could confirm that the 
implementation was different and improved.

I think some instructions on how to compile without all this bloat
is needed. It looks mainly to be used for producing documentation 
in different formats.

BR
Peter
 
> @InProceedings{paysan20,
>   author =       {Bernd Paysan and M. Anton Ertl},
>   title =        {The Grand Recognizer Unification},
>   crossref =     {euroforth20},
>   pages =        {19--22},
>   url =          {http://www.euroforth.org/ef20/papers/paysan.pdf},
>   url-slides =   {http://www.euroforth.org/ef20/papers/paysan-slides.pdf},
>   video =        {https://www.youtube.com/watch?v=VUi6uYqIbTI},
>   OPTnote =      {not refereed},
>   abstract =     {There is an obvious similarity between the search
>                   order and a recognizer sequence, which has led to
>                   similarities in proposed words (e.g.,
>                   \code{get-recognizer} is modeled on
>                   \code{get-order}).  By turning word lists into
>                   recognizers, we unify these concepts.  We also turn
>                   recognizer sequences (and be extension the search
>                   order) into a recognizer, which allows nestable
>                   recognizer sequences and wordlist sequences in the
>                   search order.  The implementation becomes simpler,
>                   too.}
> }
> @Proceedings{euroforth20,
>   title = 	 {36th EuroForth Conference},
>   booktitle = 	 {36th EuroForth Conference},
>   year = 	 {2020},
>   key =		 {EuroForth'20},
>   url =          {http://www.euroforth.org/ef20/papers/proceedings.pdf}
> }
> 
> - anton

[toc] | [prev] | [next] | [standalone]


#134940

FromHans Bezemer <the.beez.speaks@gmail.com>
Date2026-04-21 19:39 +0200
Message-ID<nnd$1e97906f$3a810a65@5852ed44ad77eeb8>
In reply to#134928
On 17-04-2026 09:29, Anton Ertl wrote:
> dxf <dxforth@gmail.com> writes:
>>> name filed: 4 byte, 3 first and last char. Only 7 bits,
>>>              8th bit counts are flags
> ...
>> Don't know who was first but Fig-forth's variable length names is something
>> that Forth Inc and pretty much everyone adopted.  Moore attempted to defend
>> '3 chars plus count' but to no avail.  That ship had sailed.
> 
> Looking at the traditional length+3 chars and
> albert@spenarnc.xs4all.nl's 3 first and last, at least one pair of
> words in Forth-94 conflicts on both systems, and WORDS could show them
> as REA?????? and REA*E, respectively.  It would be interesting to
> determine (say, by checking the words from an existing Forth system),
> which scheme produces more conflicts.
> 
> Moore continues with this approach in Color Forth, but he uses some
> compression approach to usually store more characters in the number of
> bits he reserves for the name (IIRC 2 cells, with cell sizes of 20
> bits, 18 bits, and 32 bits on different hardware).  I don't remember
> if he stores the length.
> 
> Another option would be to store a hash value that is computed using
> all characters in the name.  If a good hash function is used, the
> probability of a conflict is relatively small with, e.g. 4000 names in
> a wordlist (about the number of names that Gforth has in the Forth
> wordlist), and even the 28 bits that albert@spenarnc.xs4all.nl
> provides.  The probability of no conflict is approximately
> 
> ((2^28-1)/(2^28))^((4000*3999)/2)
> 
> i.e.
> 
> 1 28 lshift s>f fdup 1e f- fswap f/ 4000 dup 1- * 2/ s>f f** f.
> 
> The result is 0.97, i.e., there is a 3% probability of conflict for
> these numbers.
> 
> The disadvantage of this approach is that WORDS or SEE cannot even
> show the little about the name that Chuck Moore's approaches or
> albert@spenarnc.xs4all.nl's approach shows.  But then, if you are so
> pressed for memory that you use one of these approaches, why not also
> save the memory for WORDS and SEE?
> 
> Another disadvantage is that the system cannot tell if a redefinition
> warning comes from a hash conflict or from the name actually being
> redefined; but it shares this disadvantage with all approaches that do
> not store the full name.
> 
> - anton

It depends a lot on the hashing routine used. FNV1a is particularly 
good, having only 4 collisions on 215,000 words.

(https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed/145633#145633)

I use it in my uBasic/4tH interpreter to convert labels to line numbers :-)

Yeah, labels don't need to be sequential. It's not ZX BASIC. After a 
decade I still have to see a collision. Full disclosure, max. source 
size is 16K, that's about 300-440 lines.

In my only 16K like program there are about 65 subroutines, most of 'em 
one-liners. Yeah, it's been heavily Forthified. :-)

4tH itself is a pseudo compiler and has (apart from a BRANCH 
instruction) no headers. It does have a great disassembler, though. With 
symbols. ;-)

Thanks to Aaron!

Hans Bezemer

[toc] | [prev] | [next] | [standalone]


#134945

Fromalbert@spenarnc.xs4all.nl
Date2026-04-22 22:48 +0200
Message-ID<nnd$112d8b41$6de5a871@c1c07004f259db9f>
In reply to#134928
In article <2026Apr17.092944@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>Another disadvantage is that the system cannot tell if a redefinition
>warning comes from a hash conflict or from the name actually being
>redefined; but it shares this disadvantage with all approaches that do
>not store the full name.

 In this context a hash conflict is a redefinition. Avoid, unless
 you intend to hide an earlier definition.

>
>- anton

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.

[toc] | [prev] | [next] | [standalone]


#134952

FromPaul Rubin <no.email@nospam.invalid>
Date2026-04-24 10:38 -0700
Message-ID<87se8k45t1.fsf@nightsong.com>
In reply to#134945
albert@spenarnc.xs4all.nl writes:
>  In this context a hash conflict is a redefinition. Avoid,

Unclear how to avoid, other than by storing the entire name so you can
detect the conflict.  

[toc] | [prev] | [next] | [standalone]


#134964

Fromalbert@spenarnc.xs4all.nl
Date2026-04-25 11:54 +0200
Message-ID<nnd$22b8fb28$086616c8@2d67f12de53fc3fd>
In reply to#134952
In article <87se8k45t1.fsf@nightsong.com>,
Paul Rubin  <no.email@nospam.invalid> wrote:
>albert@spenarnc.xs4all.nl writes:
>>  In this context a hash conflict is a redefinition. Avoid,
>
>Unclear how to avoid, other than by storing the entire name so you can
>detect the conflict.

If you have a conflict, you rename the new offending definition,
as you do now. If you redefine a word, it is intentional, and
you can ignore the message.
ciforth can use 10,000 character names, even store it in ALLOCATEd space.

The essential point of ciforth is that there is one handle (dictionary
entry address) to characterize a word/definition/procedure/data-object.
Use that for everything to pass around.
No words with "no name", only data structures where the name is left a
zero pointer.

Not that the model can be valid even if you use 4 character names.
Jeez!

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.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.forth


csiph-web