Discussion:
Numeric string output - conspicuously absent in Forth
Add Reply
dxf
2024-04-29 05:14:58 UTC
Reply
Permalink
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output. My guess it's because the Kitt Peak Forth document
from which the first attempts at a standard were drafted had no such words.
If anyone complained about the lack they were told 'Well, you can write your
own'. Which was true but unsatisfying. It made little sense to duplicate
what was essentially factors of the standard functions. When floating-point
was standardized, it was no longer so easy to DIY numeric strings.

So how have serious forth implementations handled the Standard's lack of
numeric string output functions? Many went ahead and provided (D.) (.)
(F.) etc. On the downside specs differed from one implementation to the
next. The other approach seen is redirection which involves taking the
existing standard functions D. . F. etc and sending the output to a
buffer instead of the console. Not every forth has the means of doing
this and it likely involves more code than the previous approach.

Why am I mentioning this? As the subject line suggests, I don't see how
Forth can be taken seriously without seriously considering numeric string
output. String output allows transformation - adding thousands separators
from (D.), transforming the exponent from (FE.) to SI units, etc. Even
the tiniest of forths can provide numeric string output at a cost cheaper
than adding it afterwards.
Paul Rubin
2024-04-29 16:22:54 UTC
Reply
Permalink
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
a***@spenarnc.xs4all.nl
2024-04-29 17:54:46 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
Definitely.
: (UD.) <# #S #> ;

Actually this is a brilliant design. I was on the trail of something
similar to floating point, but I lost it.

Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
mhx
2024-04-29 19:40:10 UTC
Reply
Permalink
***@spenarnc.xs4all.nl wrote:
[..]
Post by a***@spenarnc.xs4all.nl
Definitely.
: (UD.) <# #S #> ;
Actually this is a brilliant design. I was on the trail of something
similar to floating point, but I lost it.
Can you look again? I have at least 40 different words to format
floats and for some reason each application needs yet another one.

-marcel
Anton Ertl
2024-05-01 17:12:02 UTC
Reply
Permalink
Post by mhx
[..]
Post by a***@spenarnc.xs4all.nl
Definitely.
: (UD.) <# #S #> ;
Actually this is a brilliant design. I was on the trail of something
similar to floating point, but I lost it.
Can you look again? I have at least 40 different words to format
floats and for some reason each application needs yet another one.
When I looked into FP formatting, I also wanted to do something like
the # stuff, but did not find a way to extend it to FP. What I did
instead is F.RDP (see
<https://gforth.org/manual/Floating_002dpoint-output.html>), F>STR-RDP
and F>BUF-RDP. Which of your 40 words is not covered by that? Why
not?

- 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: https://euro.theforth.net/2023
dxf
2024-05-02 04:20:50 UTC
Reply
Permalink
Post by Anton Ertl
Post by mhx
[..]
Post by a***@spenarnc.xs4all.nl
Definitely.
: (UD.) <# #S #> ;
Actually this is a brilliant design. I was on the trail of something
similar to floating point, but I lost it.
Can you look again? I have at least 40 different words to format
floats and for some reason each application needs yet another one.
When I looked into FP formatting, I also wanted to do something like
the # stuff, but did not find a way to extend it to FP. What I did
instead is F.RDP (see
<https://gforth.org/manual/Floating_002dpoint-output.html>), F>STR-RDP
and F>BUF-RDP. Which of your 40 words is not covered by that?
Marcel has one that's not unlike this:

\ (ENG.)

create si
char z c, char y c, char a c, char f c, char p c,
char n c, char u c, char m c, bl c, char k c,
char M c, char G c, char T c, char P c,

\ Convert r to string in engineering notation with SI suffix
\ prec = max significant digits
: (ENG.) ( r prec -- adr len )
precision fdp @ 2>r \ save defaults
fdp off ( prec) set-precision -1 (fe.) ( a u)
2r> fdp ! set-precision \ restore defaults
2dup [char] E split 2drop ( a u a2 u2) dup if ( not NAN/INF)
2dup 1 /string ( skip 'E') >int #24 + 3 /
dup 0 #14 within if \ SI range
si + c@ >r over swap blank
r> swap 1+ c! -trailing
end drop
then 2drop ;

behead si si
Post by Anton Ertl
Why not?
Because one function can't cover everything? OTOH having a primitive
that's predictable and comes with good options goes a long way.
Gerry Jackson
2024-04-29 19:47:10 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
It's a nice idea but the restrictions around it and the specified
implementation render it unsuitable for building upon it if you want to
write portable software. Faults with it are:

- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
- POB contents are built up from right to left, making concatenation
user hostile
- only one buffer available to the programmer
- cannot set POB size
- buffers not nestable
- POB contents can only be accessed by #> which terminates things
- system words such as .S may use the POB, thus hindering debugging
- the system need not check the POB for overflow

Some of these can be improved in a Forth system but software using the
improvements may not be portable between systems.

I've written my own version of <# etc, with the '#' replaced by '~',
that does not have the above problems. It has:

new-buffer ( "name" xt ca u ~buf-size -- ) create a new format buffer
<~ ( -- ) open a format buffer
~> ( -- ca u ) get contents of the current buffer, can be added to (has
synonym ~@
~><~ ( -- ca u ) get contents of buffer, close it and open another
~hold ( ch -- ) with synonym ~c+
~holds ( ca u -- ) with synonym ~+
~fill ( n ch -- )

~w ( n -- ) set a field width
~r ( +n -- ) set field width and right justify next conversion
~l ( -n -- ) set field width and left justify next conversion
~uc ( -- ) set upper case
~lc ( -- ) set lower case
~d ( d -- ) convert signed double integer
~i ( n -- ) convert signed integer
~ud ( ud ) convert unsigned double integer
~ui ( u -- ) convert unsigned integer
~s ( ca u -- ) hold string subject to any justification etc
~c ( ch -- ) hold character subject to any justification etc

I've used these as primitives for integer sprintf implementations
intending (when I get time and interest) to extend it to a floating
point sprintf
--
Gerry
Paul Rubin
2024-04-29 20:54:26 UTC
Reply
Permalink
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
Yeah that's a typical Forthy thing though. So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
dxf
2024-04-30 01:11:10 UTC
Reply
Permalink
Post by Paul Rubin
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
Yeah that's a typical Forthy thing though. So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
PAD ( a u -- a2 u )
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;

\ e.g. Pi 1e8 f* 0 (f.) >pad +comma cr type
Gerry Jackson
2024-04-30 19:09:34 UTC
Reply
Permalink
Post by Paul Rubin
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
Yeah that's a typical Forthy thing though. So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover
from the time 40 years ago when memory was a scarce and expensive
commodity. Things like this should be weeded out of the standard.
--
Gerry
dxf
2024-05-01 01:49:13 UTC
Reply
Permalink
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
   the system e.g. being  moved or overwritten
Yeah that's a typical Forthy thing though.  So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover from the time 40 years ago when memory was a scarce and expensive commodity. Things like this should be weeded out of the standard.
How is efficient use of a resource 'a hangover'? I've no particular allegiance
to Standard Forth and will happily argue against things that were never properly
considered e.g. the topic of this thread. Multiple HOLD buffers is like multiple
S" buffers. For some folks one is never enough.
a***@spenarnc.xs4all.nl
2024-05-01 09:25:49 UTC
Reply
Permalink
Post by dxf
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
   the system e.g. being  moved or overwritten
Yeah that's a typical Forthy thing though.  So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover from the time 40 years ago when memory was a scarce and expensive commodity. Things like this should be weeded out of the standard.
How is efficient use of a resource 'a hangover'? I've no particular allegiance
to Standard Forth and will happily argue against things that were never properly
considered e.g. the topic of this thread. Multiple HOLD buffers is like multiple
S" buffers. For some folks one is never enough.
Multiple buffers is a cludge, more so than a single buffer.
The preferred enhancement is using ALLOCATE, enhanced with a string-save
mechanism. ( $!a $@a )
ALLOCATE packets with a SIZE (Aguilar's invention?) are especially nice.

Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
dxf
2024-05-01 10:18:25 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by dxf
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
   the system e.g. being  moved or overwritten
Yeah that's a typical Forthy thing though.  So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover from the time 40 years ago when memory was a scarce and expensive commodity. Things like this should be weeded out of the standard.
How is efficient use of a resource 'a hangover'? I've no particular allegiance
to Standard Forth and will happily argue against things that were never properly
considered e.g. the topic of this thread. Multiple HOLD buffers is like multiple
S" buffers. For some folks one is never enough.
Multiple buffers is a cludge, more so than a single buffer.
The preferred enhancement is using ALLOCATE, enhanced with a string-save
ALLOCATE packets with a SIZE (Aguilar's invention?) are especially nice.
ALLOCATE - the genie (or devil) that conjures up memory out of nowhere.
Even if I had the memory to implement it I wouldn't.
Gerry Jackson
2024-05-01 10:05:32 UTC
Reply
Permalink
Post by dxf
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
   the system e.g. being  moved or overwritten
Yeah that's a typical Forthy thing though.  So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover from the time 40 years ago when memory was a scarce and expensive commodity. Things like this should be weeded out of the standard.
How is efficient use of a resource 'a hangover'?
Perhaps a better term would have been 'a consequence of'. Calling
sharing of memory between different buffers an 'efficient use of a
resource' is making a virtue of necessity 40 years ago. It isn't needed
these days. Anyway copying a string to avoid corruption of data is
hardly efficient.
Post by dxf
I've no particular allegiance
to Standard Forth and will happily argue against things that were never properly
considered e.g. the topic of this thread. Multiple HOLD buffers is like multiple
S" buffers. For some folks one is never enough.
Like Block buffers you mean where, IIRC, more than 1 was the norm.
--
Gerry
dxf
2024-05-01 12:04:23 UTC
Reply
Permalink
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
    the system e.g. being  moved or overwritten
Yeah that's a typical Forthy thing though.  So after calling #> you have
to copy the output away before doing anything else that could mess with
the POB..
Yes I know, but that shouldn't be necessary. I guess it's a hangover from the time 40 years ago when memory was a scarce and expensive commodity. Things like this should be weeded out of the standard.
How is efficient use of a resource 'a hangover'? 
Perhaps a better term would have been 'a consequence of'. Calling sharing of memory between different buffers an 'efficient use of a resource' is making a virtue of necessity 40 years ago. It isn't needed these days. Anyway copying a string to avoid corruption of data is hardly efficient.
There's no corruption or copying if the HOLD buffer is used as intended - a temporary
region for numeric conversion following which the data is sent to where it needs to go.
If a programmer elects to leave the data in the buffer and initiates another conversion,
is it the system's responsibility to find resources - or the programmer's?

As a matter of curiosity how and where does C do numeric conversion? Does it use a temp
buffer? If so, then it must do a copy to the destination.
Paul Rubin
2024-05-02 00:03:53 UTC
Reply
Permalink
Post by dxf
As a matter of curiosity how and where does C do numeric conversion?
Does it use a temp buffer? If so, then it must do a copy to the
destination.
User-supplied buffer, like

snprintf(buf, bufsize, "%d", n);

for general printf-style formatting. There is a GNU extension
asprintf(...) which allocates the string with malloc.

C++ has its own stuff that is much different.
dxf
2024-05-02 02:50:39 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
As a matter of curiosity how and where does C do numeric conversion?
Does it use a temp buffer? If so, then it must do a copy to the
destination.
User-supplied buffer, like
snprintf(buf, bufsize, "%d", n);
for general printf-style formatting. There is a GNU extension
asprintf(...) which allocates the string with malloc.
C++ has its own stuff that is much different.
Perhaps implementations vary. Subsequent to my question I remembered
I had the source for a 'small-C' for CP/M. Looking at the primitive for
sprintf I found it uses a small static buffer. The numeric string is
built there after which it's copied to the user-designated buffer.
Other than the final copy step, it's basically what forth does.
Unlike forth, C users don't get to manipulate the low-level stuff.

OT: One difference is how this C built the numeric. Digits are stored
in a forward fashion from highest to lowest. They manage this via
recursion. Here's the equivalent in forth using EMIT rather than
placing the character.

: U/MOD ( u div -- rem quot ) 0 swap um/mod ;

: .DEC ( u -- )
10 u/mod ?dup if recurse then [char] 0 + emit ;
Paul Rubin
2024-05-02 04:41:53 UTC
Reply
Permalink
Post by dxf
Perhaps implementations vary. Subsequent to my question I remembered
I had the source for a 'small-C' for CP/M. Looking at the primitive for
sprintf I found it uses a small static buffer. The numeric string is
built there after which it's copied to the user-designated buffer.
sprintf(buf, "%d", n) still works. It's like snprintf except the buffer
size is not specified. The buffer is instead assumed to be large enough
to hold the output. That can obviously be dangerous, especially
considering %s for formatting strings, so snprintf is preferred.

Using a static buffer creates obvious thread safety issues if two calls
to sprintf are active at the same time. The Linux man page for sprintf
and friends has the thread safety attribute "MT-Safe locale" for those
functions. I don't know what that means exactly though. In CP/M this
probably wasn't an issue.
dxf
2024-05-02 06:18:49 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
Perhaps implementations vary. Subsequent to my question I remembered
I had the source for a 'small-C' for CP/M. Looking at the primitive for
sprintf I found it uses a small static buffer. The numeric string is
built there after which it's copied to the user-designated buffer.
sprintf(buf, "%d", n) still works. It's like snprintf except the buffer
size is not specified. The buffer is instead assumed to be large enough
to hold the output. That can obviously be dangerous, especially
considering %s for formatting strings, so snprintf is preferred.
Using a static buffer creates obvious thread safety issues if two calls
to sprintf are active at the same time. The Linux man page for sprintf
and friends has the thread safety attribute "MT-Safe locale" for those
functions. I don't know what that means exactly though. In CP/M this
probably wasn't an issue.
WRT multi-tasking forth's HOLD buffer and PAD were designed to be task
safe. If the plan is multiple tasks should do fp output then things
such as REPRESENT's buffer would probably need protecting too. Limiting
I/O to a single task may be the easier option. Those who play with this
stuff may care to comment.
dxf
2024-05-02 06:35:08 UTC
Reply
Permalink
Post by dxf
Post by Paul Rubin
...
Using a static buffer creates obvious thread safety issues if two calls
to sprintf are active at the same time. The Linux man page for sprintf
and friends has the thread safety attribute "MT-Safe locale" for those
functions. I don't know what that means exactly though. In CP/M this
probably wasn't an issue.
WRT multi-tasking forth's HOLD buffer and PAD were designed to be task
safe. If the plan is multiple tasks should do fp output then things
such as REPRESENT's buffer would probably need protecting too.
...
Checking VFX I see they've put REPRESENT's buffer in the User area along
with under-the-hood variables related to the f/p output functions.
Anton Ertl
2024-05-03 16:49:08 UTC
Reply
Permalink
Post by dxf
If the plan is multiple tasks should do fp output then things
such as REPRESENT's buffer would probably need protecting too.
REPRESENT uses a buffer that the caller provides, so its interface is
compatible with thread-safety. However, REPRESENT is obviously based
on ecvt(), which is not thread-safe. But fortunately, if you use
glibc, there is ecvt_r(), which is thread-safe.

- 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: https://euro.theforth.net/2023
dxf
2024-05-04 05:14:42 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
If the plan is multiple tasks should do fp output then things
such as REPRESENT's buffer would probably need protecting too.
REPRESENT uses a buffer that the caller provides, so its interface is
compatible with thread-safety. However, REPRESENT is obviously based
on ecvt(), which is not thread-safe. But fortunately, if you use
glibc, there is ecvt_r(), which is thread-safe.
SwiftForth uses a static buffer for REPRESENT. I notice that when
I replaced REPRESENT and the f/p output functions I moved the buffer
to the User area. That SwiftForth hadn't done so themselves suggests
little need or customer interest. I don't know how 'multi-thread'
works in C relative to Forth as far as the user is concerned. Beyond
my pay grade.
Anton Ertl
2024-05-03 16:54:55 UTC
Reply
Permalink
Post by Paul Rubin
The Linux man page for sprintf
and friends has the thread safety attribute "MT-Safe locale" for those
functions. I don't know what that means exactly though.
That's why the man page points you to attributes(7), and when I do

man 7 attributes

it tells me that MT-Safe means "thread-safe", i.e., "safe to call in
the presence of other threads."

About the "locale" remark it says:

|Functions annotated with locale as an MT-Safety issue read from the
|locale object without any form of synchronization. Functions
|annotated with locale called concurrently with locale changes may
|behave in ways that do not correspond to any of the locales active
|during their execution, but an unpredictable mix thereof.

But you are not supposed to change the locale in a multi-threaded
program.

Anyway, the locale thing shows a problem with the suggestion to use
sprintf() instead of ecvt_r().

- 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: https://euro.theforth.net/2023
Paul Rubin
2024-05-04 20:35:04 UTC
Reply
Permalink
Post by Anton Ertl
man 7 attributes
it tells me that MT-Safe means "thread-safe", i.e., "safe to call in
the presence of other threads."
Yes I saw that, but it isn't clear to me from that description that
sprintf can safely be active in both threads at the same time.
Anton Ertl
2024-05-05 14:31:38 UTC
Reply
Permalink
Post by Paul Rubin
Post by Anton Ertl
man 7 attributes
it tells me that MT-Safe means "thread-safe", i.e., "safe to call in
the presence of other threads."
Yes I saw that, but it isn't clear to me from that description that
sprintf can safely be active in both threads at the same time.
What else would thread-safe or "multi-threading safe" mean?

- 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: https://euro.theforth.net/2023
a***@spenarnc.xs4all.nl
2024-04-30 08:38:57 UTC
Reply
Permalink
Post by Gerry Jackson
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
It's a nice idea but the restrictions around it and the specified
implementation render it unsuitable for building upon it if you want to
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
This is not a fault with <#. You can easily make it work with
ALLOCATE.
Post by Gerry Jackson
- POB contents are built up from right to left, making concatenation
user hostile
Make that a "minor inconvenience".
Post by Gerry Jackson
- only one buffer available to the programmer
See ALLOCATE.
Post by Gerry Jackson
- cannot set POB size
See ALlOCATE.
Post by Gerry Jackson
- buffers not nestable
See ALLOCATE.
Post by Gerry Jackson
- POB contents can only be accessed by #> which terminates things
???
Post by Gerry Jackson
- system words such as .S may use the POB, thus hindering debugging
See nesting
Post by Gerry Jackson
- the system need not check the POB for overflow
See ALLOCATE
Post by Gerry Jackson
Some of these can be improved in a Forth system but software using the
improvements may not be portable between systems.
They need not be. Only the spec's have to be updated.
It has been debunked numerous times, that adhering to a
common specification doesn't require a portable implementation.
Post by Gerry Jackson
I've written my own version of <# etc, with the '#' replaced by '~',
new-buffer ( "name" xt ca u ~buf-size -- ) create a new format buffer
<~ ( -- ) open a format buffer
~> ( -- ca u ) get contents of the current buffer, can be added to (has
~><~ ( -- ca u ) get contents of buffer, close it and open another
~hold ( ch -- ) with synonym ~c+
~holds ( ca u -- ) with synonym ~+
~fill ( n ch -- )
~w ( n -- ) set a field width
~r ( +n -- ) set field width and right justify next conversion
~l ( -n -- ) set field width and left justify next conversion
~uc ( -- ) set upper case
~lc ( -- ) set lower case
~d ( d -- ) convert signed double integer
~i ( n -- ) convert signed integer
~ud ( ud ) convert unsigned double integer
~ui ( u -- ) convert unsigned integer
~s ( ca u -- ) hold string subject to any justification etc
~c ( ch -- ) hold character subject to any justification etc
I've used these as primitives for integer sprintf implementations
intending (when I get time and interest) to extend it to a floating
point sprintf
You have yet to convince that these cannot be upwards compatible.

If you want printf compatibility, why not just import a c-library?
Post by Gerry Jackson
--
Gerry
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
Gerry Jackson
2024-04-30 19:02:28 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
It's a nice idea but the restrictions around it and the specified
implementation render it unsuitable for building upon it if you want to
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
This is not a fault with <#. You can easily make it work with
ALLOCATE.
So given a Forth system suppose I allocate a buffer for use with the <#
family - how do I make the existing <# definitions use that buffer
without re-defining <# etc?
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- POB contents are built up from right to left, making concatenation
user hostile
Make that a "minor inconvenience".
I don't think so
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- only one buffer available to the programmer
See ALLOCATE.
So given a Forth system I allocate an additional buffer for use with the
<# family - how do I make the existing <# definitions use that buffer
without re-defining <# etc?
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- cannot set POB size
See ALlOCATE.
So given a Forth system I .... how do I ...
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- buffers not nestable
See ALLOCATE.
Post by Gerry Jackson
- POB contents can only be accessed by #> which terminates things
???
How do you see what the buffer contains without using #> when you don't
even know the starting address?
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- system words such as .S may use the POB, thus hindering debugging
See nesting
If a Forth system uses the POB for implementing .S how do I stop it
doing so without redefining .S (easy to do I admit).
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
- the system need not check the POB for overflow
See ALLOCATE
So given a Forth system I .... how do I ...
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
Some of these can be improved in a Forth system but software using the
improvements may not be portable between systems.
Did you not read this bit before your knee-jerk reaction above? No I
thought not
Post by a***@spenarnc.xs4all.nl
They need not be. Only the spec's have to be updated.
Yeah sure - listen to the howls of outrage when changes to the ANS
standard are suggested particularly when they refer to things present
from the original implementations of Forth.
Post by a***@spenarnc.xs4all.nl
It has been debunked numerous times, that adhering to a
common specification doesn't require a portable implementation.
What has a portable implementation got to do with it, my comments were
about the using an existing Forth system that implements the <# family
doing nasty things that the standard permits such as moving the buffer
without you knowing.
Post by a***@spenarnc.xs4all.nl
Post by Gerry Jackson
I've written my own version of <# etc, with the '#' replaced by '~',
new-buffer ( "name" xt ca u ~buf-size -- ) create a new format buffer
<~ ( -- ) open a format buffer
~> ( -- ca u ) get contents of the current buffer, can be added to (has
~><~ ( -- ca u ) get contents of buffer, close it and open another
~hold ( ch -- ) with synonym ~c+
~holds ( ca u -- ) with synonym ~+
~fill ( n ch -- )
~w ( n -- ) set a field width
~r ( +n -- ) set field width and right justify next conversion
~l ( -n -- ) set field width and left justify next conversion
~uc ( -- ) set upper case
~lc ( -- ) set lower case
~d ( d -- ) convert signed double integer
~i ( n -- ) convert signed integer
~ud ( ud ) convert unsigned double integer
~ui ( u -- ) convert unsigned integer
~s ( ca u -- ) hold string subject to any justification etc
~c ( ch -- ) hold character subject to any justification etc
I've used these as primitives for integer sprintf implementations
intending (when I get time and interest) to extend it to a floating
point sprintf
You have yet to convince that these cannot be upwards compatible.
Upwards compatible with what? I wasn't intending them to be compatible
with anything.
Post by a***@spenarnc.xs4all.nl
If you want printf compatibility, why not just import a c-library?
Where's the fun in that?
--
Gerry
a***@spenarnc.xs4all.nl
2024-05-01 10:40:19 UTC
Reply
Permalink
In article <v0rf84$2kkku$***@dont-email.me>,
Gerry Jackson <do-not-***@swldwa.uk> wrote:
<SNIP>
Post by Gerry Jackson
What has a portable implementation got to do with it, my comments were
about the using an existing Forth system that implements the <# family
doing nasty things that the standard permits such as moving the buffer
without you knowing.
That is the problem. I talk about modifying a Forth system.

*** #> ***
Description: Terminates numeric output conversion by dropping 'd',
leaving the formatted string 'sc' .

There is no reason, to not add:
In a portable program you must assume that is the same
buffer and can be overwritten by a subsequent use of <# # #>.
In gerryforth however this 'sc' is permanent until it is
garbage collected.
[The negative implication that a standard system must overwrite
this buffer is not correct.]

Next step is that this is generally expected from a mature system and
that in the documentation requirements it is to be stated that this is
a static buffer or not.

<SNIP>
Post by Gerry Jackson
Post by a***@spenarnc.xs4all.nl
If you want printf compatibility, why not just import a c-library?
Where's the fun in that?
I had more fun in implementing the .FORMAT screen that does what
c does, simpler and more flexible. Isn't that what Forth is all
about?
(It has a wordlist FORMAT-WID where you can add new formatting words,
that were previously missing.)
I can't resist the temptation to quote it here.
(It builds on the tiny string abstraction $! $@ $/ )

--------------------------8<-------------------------------
( FORMAT FORMAT&EVAL .FORMAT ) \ AH&CH C2feb15
DATA CRS$ 4096 ALLOT \ ":2" WANTED
NAMESPACE FORMAT-WID FORMAT-WID DEFINITIONS
: c CRS$ $C+ ; : n ^J c ; : r ^M c ; \ Add single char's
: d S>D 0 (D.R) CRS$ $+! ; \ Add INT as a string.
: s CRS$ $+! ; \ Add a STRING as such.
PREVIOUS DEFINITIONS
\ Format the first part of STRING, up till %, leave REST.
: _plain &% $/ CRS$ $+! ;
\ Format X with first word of STRING, up till BL, leave REST.
: _format BL $/ 2SWAP >R >R 'FORMAT-WID >WID (FIND) NIP NIP
DUP 0= 51 ?ERROR EXECUTE R> R> ;
\ Format X1 .. Xn using the format STRING.
: FORMAT 0 CRS$ ! BEGIN DUP WHILE _plain DUP IF _format THEN
REPEAT 2DROP CRS$ $@ ;
: FORMAT&EVAL FORMAT EVALUATE ; : .FORMAT FORMAT TYPE ;
--------------------------8<-------------------------------

Now the class building screen can do things as
BLD$ $@ NAME$ $@ ": BUILD-%s HERE >R %s R> ;" FORMAT&EVAL
generating a definition for class POINT
: BUILD-POINT HERE >R , , R> ;
Post by Gerry Jackson
Gerry
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
sjack
2024-04-30 10:16:41 UTC
Reply
Permalink
Frog code (Fig not standard):
[#] pno.d -- Pictured Numeric Output exploits
--.
[r] #>S ( -- s )
-- Pictured numeric returning (counted) string
: #>S #> HOLD 1- ;

-- String, S , in Frog code is single address pointing to byte
-- counted string.
-- <# ... #> ( a u ) TYPE
-- <# ... #>S ( a ) TELL
--.
[r] S<# ( n -- d ) Immediate
-- Macro for Single-number pictured numeric
: S<# "ZERO <#" EVAL ; IMM

-- Frog leaves '<#' to work with double number and
-- uses macro 'S<#' as indicament of working with single number.
-- 666. <# ... #> TYPE
-- 666 S<# ... #>S TELL
--.
[r] PNO buffer
The PNO can be any buffer by pointing HLD to the buffer's end and
using an alternative to '>#' :

mpad 256 + tmp!
tmp@ hld !
"[m" holds
27 hold
"world" holds
46 hold
"[0;33;40mhello" holds
27 hold
i. hld @ tmp@ om type --> hello.world ( yellow on black )
--.
[r] Source input buffer
-- Source input buffer is ring buffer for strings
: <#IB 256 SIB + DUP HLD ! TMP! ;
: IB#> 2DROP HLD @ TMP@ OM ;
: SIB#>S HLD @ TMP@ OM HOLD 1- ;

-- sib ( u -- u a )
: <#IB 256 SIB + DUP HLD ! TMP! ;
: IB#> 2DROP HLD @ TMP@ OM ;
: SIB#>S HLD @ TMP @ OM hold 1- ;

<#ib "[m" holds 27 hold SIB#>S
<#ib "[0;33;40m" holds 27 hold SIB#>S
2dup
1 text Hello World!
i. tell pad tell tell --> Hello World! ( yellow on black)
1 text How are you?
i. tell pad tell tell --> How are you? ( yellow on black)
--.
[s]
OM ( a1 a2 -- a1 u ) over -
tell ( a ) count type
sib ( u -- u a ) \ a is buffer from ring of size u+2; last chr is null
\ used for counted string, null terminated string or
\ both.
i. \ print ' --> '
--.
[#] //
sjack
2024-04-30 11:23:00 UTC
Reply
Permalink
(The last had 3 redundant lines that needed deleting.)

Frog code (Fig not standard):
[#] pno.d -- Pictured Numeric Output exploits
--.
[r] #>S ( -- s )
-- Pictured numeric returning (counted) string
: #>S #> HOLD 1- ;

-- String, S , in Frog code is single address pointing to byte
-- counted string.
-- <# ... #> ( a u ) TYPE
-- <# ... #>S ( a ) TELL
--.
[r] S<# ( n -- d ) Immediate
-- Macro for Single-number pictured numeric
: S<# "ZERO <#" EVAL ; IMM

-- Frog leaves '<#' to work with double number and
-- uses macro 'S<#' as indicament of working with single number.
-- 666. <# ... #> TYPE
-- 666 S<# ... #>S TELL
--.
[r] PNO buffer
The PNO can be any buffer by pointing HLD to the buffer's end and
using an alternative to '>#' :

mpad 256 + tmp!
tmp@ hld !
"[m" holds
27 hold
"world" holds
46 hold
"[0;33;40mhello" holds
27 hold
i. hld @ tmp@ om type --> hello.world ( yellow on black )
--.
[r] Source input buffer
-- Source input buffer is ring buffer for strings
: <#IB 256 SIB + DUP HLD ! TMP! ;
: IB#> 2DROP HLD @ TMP@ OM ;
: SIB#>S HLD @ TMP@ OM HOLD 1- ;

<#ib "[m" holds 27 hold SIB#>S
<#ib "[0;33;40m" holds 27 hold SIB#>S
2dup
1 text Hello World!
i. tell pad tell tell --> Hello World! ( yellow on black)
1 text How are you?
i. tell pad tell tell --> How are you? ( yellow on black)
--.
[s]
OM ( a1 a2 -- a1 u ) over -
tell ( a ) count type
sib ( u -- u a ) \ a is buffer from ring of size u+2; last chr is null
\ used for counted string, null terminated string or
\ both.
i. \ print ' --> '
--.
[#] //
Anton Ertl
2024-05-01 17:19:49 UTC
Reply
Permalink
Post by Gerry Jackson
- the pictured output buffer (POB) may be transient, can be corrupted by
the system e.g. being moved or overwritten
It is invalidated by anything that ALLOTs or COMPILE,s. I have not
found that to be a problem.

However, with the same interface (less restrictions) one could
implement a growable HOLD buffer that is not located relative to HERE
and is therefore not destroyed by ALLOT and COMPILE,.
Post by Gerry Jackson
- POB contents are built up from right to left, making concatenation
user hostile
It's designed for converting numbers to strings, that means it builds
up the number from the least significant digit. If you want something
for concatenating strings, use something else.
Post by Gerry Jackson
- only one buffer available to the programmer
Gforth supports nested generation of numbers in that single buffer:

<<# starts a new (nested) number); use that instead of <#
#> gives you the string, still holding it
#>> releases the memory for the string

E.g.:

: my-u. ( u -- )
\ Simplest use of pns.. behaves like Standard u.
0 \ convert to unsigned double
<<# \ start conversion
#s \ convert all digits
#> \ complete conversion
TYPE SPACE \ display, with trailing space
#>> ; \ release hold area

More docs at <https://gforth.org/manual/Formatted-numeric-output.html>

I found that sufficient for my usage.
Post by Gerry Jackson
- cannot set POB size
If anything, the HOLD buffer should grow automatically.
Post by Gerry Jackson
- buffers not nestable
Fixed in Gforth, see above.
Post by Gerry Jackson
- POB contents can only be accessed by #> which terminates things
You can do

( ud ) 2DUP #> ( ud c-addr u )

to get the string without destroying the number, but I have not
found the need to do that. That's standard usage.
Post by Gerry Jackson
- system words such as .S may use the POB, thus hindering debugging
- the system need not check the POB for overflow
In Gforth .S uses <<# ... #>> and thus avoids destroying the existing
stuff in the HOLD buffer.
Post by Gerry Jackson
Some of these can be improved in a Forth system but software using the
improvements may not be portable between systems.
For debugging, this is not a big problem: Debug on Gforth, then run on
a less capable system.
Post by Gerry Jackson
I've written my own version of <# etc, with the '#' replaced by '~',
In which way does it solve the compatibility problem? If that is done
by loading the source code for these words, one could also reimplement
the standard words, with enhancements like <<# #>> to address the
issues.
Post by Gerry Jackson
~><~ ( -- ca u ) get contents of buffer, close it and open another
What invalidates the string?

- 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: https://euro.theforth.net/2023
dxf
2024-04-30 08:45:20 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
Only as a missed opportunity. There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.

\ Print string right-justified in a field of width chars
: S.R ( adr len width -- ) over - spaces type ; ( eForth)

\ Numeric string output
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len ) 0 (d.) ;
: (.) ( n -- adr len ) s>d (d.) ;

\ Forth-79/83/94
: D. ( d -- ) (d.) type space ;
: U. ( u -- ) 0 d. ;
: . ( n -- ) s>d d. ;
: D.R ( d w -- ) >r (d.) r> s.r ;
: U.R ( u w -- ) 0 swap d.r ;
: .R ( n w -- ) >r s>d r> d.r ;
mhx
2024-04-30 09:40:23 UTC
Reply
Permalink
Post by dxf
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
Only as a missed opportunity. There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.
\ Print string right-justified in a field of width chars
: S.R ( adr len width -- ) over - spaces type ; ( eForth)
\ Numeric string output
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len ) 0 (d.) ;
: (.) ( n -- adr len ) s>d (d.) ;
\ Forth-79/83/94
: D. ( d -- ) (d.) type space ;
: U. ( u -- ) 0 d. ;
: . ( n -- ) s>d d. ;
: D.R ( d w -- ) >r (d.) r> s.r ;
: U.R ( u w -- ) 0 swap d.r ;
: .R ( n w -- ) >r s>d r> d.r ;
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if
you want to do it yourself in a portable way. The other reason
is probably that double precision is needed to implement this,
but the Double-Number word set is optional.

So far for speculation.

-marcel
a***@spenarnc.xs4all.nl
2024-04-30 10:07:11 UTC
Reply
Permalink
Post by mhx
Post by dxf
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
Only as a missed opportunity. There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.
\ Print string right-justified in a field of width chars
: S.R ( adr len width -- ) over - spaces type ; ( eForth)
\ Numeric string output
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len ) 0 (d.) ;
: (.) ( n -- adr len ) s>d (d.) ;
\ Forth-79/83/94
: D. ( d -- ) (d.) type space ;
: U. ( u -- ) 0 d. ;
: . ( n -- ) s>d d. ;
: D.R ( d w -- ) >r (d.) r> s.r ;
: U.R ( u w -- ) 0 swap d.r ;
: .R ( n w -- ) >r s>d r> d.r ;
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if
you want to do it yourself in a portable way. The other reason
is probably that double precision is needed to implement this,
but the Double-Number word set is optional.
So far for speculation.
I guess that is right.

Moore hated double precision.
(I kind of like them, it is convenient for euler project problems.)
E.g.
-1. <# #S #> TYPE
340282366920938463463374607431768211455

It can be argued that for a simple kernel doubles are not needed.
I left it out for yourforth, 1) modifying #-words to %-words.
yourforth is slightly over 200 words, including my hobby horses, like
1) An ISO alternative for jonesforth.
Post by mhx
-marcel
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
sjack
2024-04-30 11:34:59 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by mhx
Post by dxf
Post by Paul Rubin
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery. Does that count?
Only as a missed opportunity. There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.
\ Print string right-justified in a field of width chars
: S.R ( adr len width -- ) over - spaces type ; ( eForth)
\ Numeric string output
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len ) 0 (d.) ;
: (.) ( n -- adr len ) s>d (d.) ;
\ Forth-79/83/94
: D. ( d -- ) (d.) type space ;
: U. ( u -- ) 0 d. ;
: . ( n -- ) s>d d. ;
: D.R ( d w -- ) >r (d.) r> s.r ;
: U.R ( u w -- ) 0 swap d.r ;
: .R ( n w -- ) >r s>d r> d.r ;
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if
you want to do it yourself in a portable way. The other reason
is probably that double precision is needed to implement this,
but the Double-Number word set is optional.
So far for speculation.
I guess that is right.
Moore hated double precision.
(I kind of like them, it is convenient for euler project problems.)
E.g.
-1. <# #S #> TYPE
340282366920938463463374607431768211455
It can be argued that for a simple kernel doubles are not needed.
I left it out for yourforth, 1) modifying #-words to %-words.
yourforth is slightly over 200 words, including my hobby horses, like
1) An ISO alternative for jonesforth.
Post by mhx
-marcel
Groetjes Albert
Didn't mean to kill your article; was trying to kill mine.
dxf
2024-05-01 03:26:36 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
...
Moore hated double precision.
From his ANS exit speech? Perhaps he was looking for things to disagree
with. Whatever precipitated his leaving, it marked the end of his
involvement with Forth standards. I imagine it was a weight off his
shoulders. It was for me when I left.
Post by a***@spenarnc.xs4all.nl
(I kind of like them, it is convenient for euler project problems.)
E.g.
-1. <# #S #> TYPE
340282366920938463463374607431768211455
It can be argued that for a simple kernel doubles are not needed.
I left it out for yourforth, 1) modifying #-words to %-words.
yourforth is slightly over 200 words, including my hobby horses, like
1) An ISO alternative for jonesforth.
It's hard to ignore mixed math especially when your processor supports it.
It gives Forth an advantage over languages such as C .
Paul Rubin
2024-05-01 03:37:50 UTC
Reply
Permalink
Post by dxf
Post by a***@spenarnc.xs4all.nl
Moore hated double precision.
From his ANS exit speech?
Yeah I'm puzzled too. I remember hearing someplace that m*/ was one of
his prouder creations. It requires a triple precision intermediate
product, so it is hard to implement in C.
c
Stephen Pelc
2024-05-02 14:00:28 UTC
Reply
Permalink
Post by Paul Rubin
Post by dxf
Post by a***@spenarnc.xs4all.nl
Moore hated double precision.
From his ANS exit speech?
Yeah I'm puzzled too. I remember hearing someplace that m*/ was one of
his prouder creations. It requires a triple precision intermediate
product, so it is hard to implement in C.
c
Neither Forth nor C give direct access to the carry and overflow flags, yet
we and many others have written M*/ in high level Forth for decades.
--
Stephen Pelc, ***@vfxforth.com
MicroProcessor Engineering, Ltd. - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)78 0390 3612, +34 649 662 974
http://www.mpeforth.com
MPE website
http://www.vfxforth.com/downloads/VfxCommunity/
downloads
minforth
2024-05-02 14:37:03 UTC
Reply
Permalink
Post by Stephen Pelc
Neither Forth nor C give direct access to the carry and overflow flags, yet
we and many others have written M*/ in high level Forth for decades.
Today most C compilers offer some intrinsics beyound classic limited
arithmetic,
eg for addition with carry.
dxf
2024-05-02 23:50:50 UTC
Reply
Permalink
Post by minforth
Post by Stephen Pelc
Neither Forth nor C give direct access to the carry and overflow flags,
yet
Post by Stephen Pelc
we and many others have written M*/ in high level Forth for decades.
Today most C compilers offer some intrinsics beyound classic limited
arithmetic,
eg for addition with carry.
That's been tried in forth e.g. MVP math and f/p extensions. IIRC the
results were neither fast nor pretty. Trying to emulate machine code
at this level appears to be of dubious benefit.
minforth
2024-05-03 19:55:46 UTC
Reply
Permalink
Post by dxf
That's been tried in forth e.g. MVP math and f/p extensions. IIRC the
results were neither fast nor pretty. Trying to emulate machine code
at this level appears to be of dubious benefit.
Intrinsics ARE assembler code.
Use gdb to inspect the result.
If you can't in your DOS world, try godbolt.
Anton Ertl
2024-05-03 16:33:17 UTC
Reply
Permalink
Post by minforth
Today most C compilers offer some intrinsics beyound classic limited
arithmetic,
eg for addition with carry.
Yes. However, when I tried these, the code that came out was not as
well as I would have liked; see
<***@mips.complang.tuwien.ac.at> and
<***@mips.complang.tuwien.ac.at>.

Last I tried it, in a sequence of a few such intrinsics the compilers
do ok between the intrinsics, but produce bad code at the start and
the end of the sequence.

- 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: https://euro.theforth.net/2023
minforth
2024-05-03 20:16:31 UTC
Reply
Permalink
Post by Anton Ertl
Post by minforth
Today most C compilers offer some intrinsics beyound classic limited
arithmetic, eg for addition with carry.
Yes. However, when I tried these, the code that came out was not as
well as I would have liked; see
Last I tried it, in a sequence of a few such intrinsics the compilers
do ok between the intrinsics, but produce bad code at the start and
the end of the sequence.
I was also a little underwhelmed. But at least they are there and can
help to avoid some awkward comparisons or extra operations. For high
speed, there is always the option of using C's built-in assembler
directly. The nice thing is that you have the freedom of choice.
Anton Ertl
2024-05-04 16:11:36 UTC
Reply
Permalink
Post by minforth
Post by Anton Ertl
Last I tried it, in a sequence of a few such intrinsics the compilers
do ok between the intrinsics, but produce bad code at the start and
the end of the sequence.
I was also a little underwhelmed. But at least they are there and can
help to avoid some awkward comparisons or extra operations.
Yes, the carry-in support is not so great, but for checking overflow,
these extensions are fine, and Bernd Paysan recently added code to
Gforth that uses gcc's __builtin_add_overflow() (if present) to
implement (+LOOP). As a consequence, (+LOOP) became a little shorter.
E.g.:

with without
__builtin_add_overflow()
add rbx,$10 add r13,$10
mov rax,[r14] mov rax,[r10]
add r13,$08 add r11,$08
mov rsi,-$08[rbx] mov rsi,-$08[r13]
lea rdx,[r8][rax] mov rdx,rax
sub rax,$08[r14] sub rdx,$08[r10]
btc rax,$3F add rax,rbx
mov [r14],rdx lea rcx,[rbx][rdx]
add rax,r8 mov [r10],rax
mov r8,$00[r13] xor rcx,rdx
jo x xor rdx,rbx
mov rax,[rsi] mov rbx,[r11]
mov rbx,rsi test rcx,rdx
jmp eax js x
x: mov rax,[rbx] mov rax,[rsi]
jmp eax mov r13,rsi
jmp eax
x: mov rax,$00[r13]
jmp eax

However, it turns out that on RISC-V (which does not have an overflow
flag) the code produced by gcc for our (+LOOP) with
__builtin_add_overflow() is worse than for (+LOOP) without.

- 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: https://euro.theforth.net/2023
minforth
2024-05-03 20:19:40 UTC
Reply
Permalink
Post by Anton Ertl
Post by minforth
Today most C compilers offer some intrinsics beyound classic limited
arithmetic, eg for addition with carry.
Last I tried it, in a sequence of a few such intrinsics the compilers
do ok between the intrinsics, but produce bad code at the start and
the end of the sequence.
I was also a little underwhelmed. But at least they are there and can
help to avoid some awkward comparisons or extra operations. For high
speed, there is always the option of using C's built-in assembler
directly. The nice thing is that you have the freedom of choice.
a***@spenarnc.xs4all.nl
2024-05-01 08:54:28 UTC
Reply
Permalink
Post by dxf
Post by a***@spenarnc.xs4all.nl
...
Moore hated double precision.
From his ANS exit speech? Perhaps he was looking for things to disagree
with. Whatever precipitated his leaving, it marked the end of his
involvement with Forth standards. I imagine it was a weight off his
shoulders. It was for me when I left.
Post by a***@spenarnc.xs4all.nl
(I kind of like them, it is convenient for euler project problems.)
E.g.
-1. <# #S #> TYPE
340282366920938463463374607431768211455
It can be argued that for a simple kernel doubles are not needed.
I left it out for yourforth, 1) modifying #-words to %-words.
yourforth is slightly over 200 words, including my hobby horses, like
1) An ISO alternative for jonesforth.
It's hard to ignore mixed math especially when your processor supports it.
It is certainly an advantage if you want to build multiple precision
words. Certain implementations become cleaner, e.g. fixed point.
Post by dxf
It gives Forth an advantage over languages such as C .
True, but not for many people, in yourforth is it out of place

Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
dxf
2024-05-01 09:53:31 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by dxf
...
It's hard to ignore mixed math especially when your processor supports it.
It is certainly an advantage if you want to build multiple precision
words. Certain implementations become cleaner, e.g. fixed point.
Post by dxf
It gives Forth an advantage over languages such as C .
True, but not for many people, in yourforth is it out of place
For forth the convention has been to use doubles as the basis for input/output.
My first forth - Tiny Forth 64 - was a fig-forth that had been modified to use
singles. On discovering this I was most disappointed - the consequence of which
was I hardly spent any time with it. Apparently there was a version for the
VIC-20 which would explain the need to save bytes where possible. For the C64,
however, there was little justification.
dxf
2024-04-30 10:36:18 UTC
Reply
Permalink
Post by mhx
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery.  Does that count?
Only as a missed opportunity.  There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.
\ Print string right-justified in a field of width chars
: S.R ( adr len width -- )  over - spaces type ; ( eForth)
\ Numeric string output
: (D.) ( d -- adr len )  tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len )  0 (d.) ;
: (.) ( n -- adr len )  s>d (d.) ;
\ Forth-79/83/94
: D. ( d -- )  (d.) type space ;
: U. ( u -- )  0 d. ;
: . ( n -- )  s>d d. ;
: D.R ( d w -- )  >r (d.) r> s.r ;
: U.R ( u w -- )  0 swap d.r ;
: .R ( n w -- )  >r s>d r> d.r ;
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if you want to do it yourself in a portable way. The other reason
is probably that double precision is needed to implement this,
but the Double-Number word set is optional.
So far for speculation.
iForth users don't need to speculate since (D.) (.) etc. are provided for them.
sjack
2024-04-30 11:33:27 UTC
Reply
Permalink
Post by dxf
Post by mhx
Post by dxf
For reasons one can only speculate Forth Standards have by and large ignored
numeric string output.
There is the <# ... #> machinery.  Does that count?
Only as a missed opportunity.  There's no cheaper way of adding string
functions than the following and it was amiss of the Standard not to
offer it.
\ Print string right-justified in a field of width chars
: S.R ( adr len width -- )  over - spaces type ; ( eForth)
\ Numeric string output
: (D.) ( d -- adr len )  tuck dabs <# #s rot sign #> ;
: (U.) ( u -- adr len )  0 (d.) ;
: (.) ( n -- adr len )  s>d (d.) ;
\ Forth-79/83/94
: D. ( d -- )  (d.) type space ;
: U. ( u -- )  0 d. ;
: . ( n -- )  s>d d. ;
: D.R ( d w -- )  >r (d.) r> s.r ;
: U.R ( u w -- )  0 swap d.r ;
: .R ( n w -- )  >r s>d r> d.r ;
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if you want to do it yourself in a portable way. The other reason
is probably that double precision is needed to implement this,
but the Double-Number word set is optional.
So far for speculation.
iForth users don't need to speculate since (D.) (.) etc. are provided for them.
Hope I didn't kill your article. Had made correction to mine and tried
to kill original but it looked to kill yours and alberts as well.
Anton Ertl
2024-05-01 17:48:46 UTC
Reply
Permalink
Post by mhx
The only words that are necessary to define these on your own are
<# # #> DABS and SIGN. There is a reason to define these in the
Standard: the hardware details of a number need to be known if
you want to do it yourself in a portable way.
All these words can be written with other standard words, in
particular UM/MOD, DNEGATE, D0< (some of which are in the double
wordset, however, but so is DABS).

- 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: https://euro.theforth.net/2023
Anton Ertl
2024-05-01 17:57:31 UTC
Reply
Permalink
Post by dxf
So how have serious forth implementations handled the Standard's lack of
numeric string output functions? Many went ahead and provided (D.) (.)
(F.) etc.
Gforth does not, and does not have factors that correspond to (D.) or
(.), and any such factors, if they existed, would put the onus on the
user to release the memory for the string with #>>.
Post by dxf
The other approach seen is redirection which involves taking the
existing standard functions D. . F. etc and sending the output to a
buffer instead of the console.
Yes, that's >STRING-EXECUTE in Gforth.
Post by dxf
String output allows transformation - adding thousands separators
from (D.)
Please demonstrate that that's less effort than using #, HOLD etc. for
that purpose.

- 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: https://euro.theforth.net/2023
dxf
2024-05-02 02:14:31 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
So how have serious forth implementations handled the Standard's lack of
numeric string output functions? Many went ahead and provided (D.) (.)
(F.) etc.
Gforth does not, and does not have factors that correspond to (D.) or
(.), and any such factors, if they existed, would put the onus on the
user to release the memory for the string with #>>.
What does that mean? Are you saying GForth users can't expect the following
standard code to function the same as in other forths?

: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
Post by Anton Ertl
Post by dxf
The other approach seen is redirection which involves taking the
existing standard functions D. . F. etc and sending the output to a
buffer instead of the console.
Yes, that's >STRING-EXECUTE in Gforth.
Post by dxf
String output allows transformation - adding thousands separators
from (D.)
Please demonstrate that that's less effort than using #, HOLD etc. for
that purpose.
I've demonstrated that it's cheaper and easier to provide string numerics
from the get-go than to provide them later. And yes, adding thousands
separators to an integer or floating-point string (works for both) requires
but a few string operators one likely already has. I posted the code just
recently. Perhaps you missed it.

\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;

\ e.g. Pi 1e8 f* 0 (f.) >pad +comma cr type
Anton Ertl
2024-05-03 17:04:20 UTC
Reply
Permalink
Post by dxf
Post by Anton Ertl
Post by dxf
So how have serious forth implementations handled the Standard's lack of
numeric string output functions? Many went ahead and provided (D.) (.)
(F.) etc.
Gforth does not, and does not have factors that correspond to (D.) or
(.), and any such factors, if they existed, would put the onus on the
user to release the memory for the string with #>>.
What does that mean? Are you saying GForth users can't expect the following
standard code to function the same as in other forths?
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
No. What in the sentence above makes you think so?

It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
use them in the following way:

( d ) (D.) ( do something with the string, and when you are done:) #>>
Post by dxf
Post by Anton Ertl
Post by dxf
String output allows transformation - adding thousands separators
from (D.)
Please demonstrate that that's less effort than using #, HOLD etc. for
that purpose.
I've demonstrated that it's cheaper and easier to provide string numerics
from the get-go than to provide them later. And yes, adding thousands
separators to an integer or floating-point string (works for both) requires
but a few string operators one likely already has. I posted the code just
recently. Perhaps you missed it.
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
: u._ ( u -- )
0 <# begin
3 0 do
# 2dup 0. d= if
#> type unloop exit then
loop
'_' hold
again ;

The latter looks simpler to me.

Something that can be applied to any of the zoo of .-like words is a
good idea, though.

Let's see how +COMMA fares

: +COMMA ( a1 u1 -- a2 u2 ) compiled
<# [char] . split 2swap shold
*the terminal*:12:16: error: Undefined word
<# [char] . >>>split<<< 2swap shold

So it needs additional complexity. Anyway, assuming that is fixed,
you would +COMMA work with the (D.) you are advocating?

An alternative approach to this kind of postprocessing is to be able
to plug something into the # used in front of a decimal point (of
course this would only work for words built with this pluggable #).
The usage might be something like:

1234567890 ' #3_ ' . #execute

The implementation of #3_ might be something like:

: #3_ ( u1 d1 -- u2 d2 )
rot dup 0> if
dup 3 mod 0= if
'_' hold
then
then
-rot basic-# ;

Of course, . etc. would have to be adapted, too.

- 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: https://euro.theforth.net/2023
dxf
2024-05-04 02:40:43 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
Post by Anton Ertl
Post by dxf
So how have serious forth implementations handled the Standard's lack of
numeric string output functions? Many went ahead and provided (D.) (.)
(F.) etc.
Gforth does not, and does not have factors that correspond to (D.) or
(.), and any such factors, if they existed, would put the onus on the
user to release the memory for the string with #>>.
What does that mean? Are you saying GForth users can't expect the following
standard code to function the same as in other forths?
: (D.) ( d -- adr len ) tuck dabs <# #s rot sign #> ;
No. What in the sentence above makes you think so?
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Post by Anton Ertl
Post by dxf
...
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
: u._ ( u -- )
0 <# begin
3 0 do
# 2dup 0. d= if
#> type unloop exit then
loop
'_' hold
again ;
The latter looks simpler to me.
Will you write another separator function for floats?
+COMMA handles both and is economic:

355000000 113 / (.) >pad +comma cr type
3,141,592 ok

Pi 1e6 f* -1 (f.) >pad +comma cr type
3,141,592.6535897932 ok

1e 0e f/ -1 (f.) >pad +comma cr type
+INF ok
Post by Anton Ertl
...
Let's see how +COMMA fares
: +COMMA ( a1 u1 -- a2 u2 ) compiled
<# [char] . split 2swap shold
*the terminal*:12:16: error: Undefined word
<# [char] . >>>split<<< 2swap shold
So it needs additional complexity. Anyway, assuming that is fixed,
Requirements were: "a few string operators one likely already has"

: SHOLD HOLDS ;

: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by Anton Ertl
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
1- 2dup + c@ ;

: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;

Nothing there that forthers wouldn't have seen or used before.
Anton Ertl
2024-05-05 15:07:09 UTC
Reply
Permalink
[...]
Post by dxf
Post by Anton Ertl
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Of course not, because standard Forth has no word (D.).
Post by dxf
Post by Anton Ertl
Post by dxf
...
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
: u._ ( u -- )
0 <# begin
3 0 do
# 2dup 0. d= if
#> type unloop exit then
loop
'_' hold
again ;
The latter looks simpler to me.
Will you write another separator function for floats?
355000000 113 / (.) >pad +comma cr type
3,141,592 ok
Pi 1e6 f* -1 (f.) >pad +comma cr type
3,141,592.6535897932 ok
1e 0e f/ -1 (f.) >pad +comma cr type
+INF ok
Post by Anton Ertl
...
Let's see how +COMMA fares
: +COMMA ( a1 u1 -- a2 u2 ) compiled
<# [char] . split 2swap shold
*the terminal*:12:16: error: Undefined word
<# [char] . >>>split<<< 2swap shold
So it needs additional complexity. Anyway, assuming that is fixed,
Requirements were: "a few string operators one likely already has"
: SHOLD HOLDS ;
: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by Anton Ertl
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;
Nothing there that forthers wouldn't have seen or used before.
So your complete setup is

: SHOLD HOLDS ;

: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by dxf
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
1- 2dup + c@ ;

: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;

\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;

And it works fine. Of course, because it uses <#, it does not work
with the nesting feature:

#12345. <<# #s #67890. <<# #s #> cr type #>> #> cr type #>>

prints

67890
12345

but

#12345. <<# #s #67890. <<# #s #> +comma cr type #>> #> cr type #>>

prints

67,890
*the terminal*:30:49: error: Result out of range
#12345. <<# #s #67890. <<# #s #> +comma cr type >>>#>><<< #> cr type #>>
Backtrace:
kernel/nio.fs:63:44: 0 $7FE0F9CB8690 throw

But that could be fixed by using <<# in +COMMA.

- 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: https://euro.theforth.net/2023
a***@spenarnc.xs4all.nl
2024-05-05 23:01:25 UTC
Reply
Permalink
Post by Anton Ertl
[...]
Post by dxf
Post by Anton Ertl
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Of course not, because standard Forth has no word (D.).
Indeed, surprisingly, but every Forth made in the Netherlands
apparently has at least (D.R) that was already present in figForth or
an equivalent to (D.).
In my experience those words that leave a string and doesnot TYPE immediately
are pretty essential. The fact that #> may refer to a static buffer
cannot be concealed anyway.
Post by Anton Ertl
- anton
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
dxf
2024-05-06 03:44:25 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by Anton Ertl
[...]
Post by dxf
Post by Anton Ertl
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Of course not, because standard Forth has no word (D.).
Indeed, surprisingly, but every Forth made in the Netherlands
apparently has at least (D.R) that was already present in figForth or
an equivalent to (D.).
In my experience those words that leave a string and doesnot TYPE immediately
are pretty essential.
Indeed - what this thread was intended to convey. It's a pity Forth Standards
just ignored it with the result too many implementations also ignore it.
Post by a***@spenarnc.xs4all.nl
The fact that #> may refer to a static buffer
cannot be concealed anyway.
And with high-end forths offering circular buffers for temp string storage it
ought not to be a problem. VFX has >SYSPAD and SwiftForth something similar.
Thus far PAD has sufficed me. I'll add complexity when and if I need it.
a***@spenarnc.xs4all.nl
2024-05-06 20:24:52 UTC
Reply
Permalink
Post by dxf
Post by a***@spenarnc.xs4all.nl
Post by Anton Ertl
[...]
Post by dxf
Post by Anton Ertl
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Of course not, because standard Forth has no word (D.).
Indeed, surprisingly, but every Forth made in the Netherlands
apparently has at least (D.R) that was already present in figForth or
an equivalent to (D.).
In my experience those words that leave a string and doesnot TYPE immediately
are pretty essential.
Indeed - what this thread was intended to convey. It's a pity Forth Standards
just ignored it with the result too many implementations also ignore it.
I remarked that all Forth in the Netherlands has such a word.
According Anton Ertl this is "not relevant".
Also that swiftforth has defined D. as
: D. (D.) TYPE SPACE ;
is not relevant.
Post by dxf
Post by a***@spenarnc.xs4all.nl
The fact that #> may refer to a static buffer
cannot be concealed anyway.
And with high-end forths offering circular buffers for temp string storage it
ought not to be a problem. VFX has >SYSPAD and SwiftForth something similar.
Thus far PAD has sufficed me. I'll add complexity when and if I need it.
As discussed, the programmer interface need not change.

Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
Anton Ertl
2024-05-06 17:50:34 UTC
Reply
Permalink
Post by a***@spenarnc.xs4all.nl
Post by Anton Ertl
[...]
Post by dxf
Post by Anton Ertl
It means: Gforth does not provide (D.) and does not have factors that
correspond to (D.) or (.). If it had such factors, you would have to
( d ) (D.) ( do something with the string, and when you are done:) #>>
Standard Forth makes no such instruction.
Of course not, because standard Forth has no word (D.).
Indeed, surprisingly, but every Forth made in the Netherlands
apparently has at least (D.R) that was already present in figForth or
an equivalent to (D.).
What every Forth made in the Netherlands has is not relevant for the
issue at hand. fig-Forth does not have (D.R); see, e.g.,
<http://www.stackosaurus.com/figforth/fig-FORTH_Glossary_2017.pdf>.
Post by a***@spenarnc.xs4all.nl
In my experience those words that leave a string and doesnot TYPE immediately
are pretty essential.
The fact that #> may refer to a static buffer
cannot be concealed anyway.
The HOLD buffer has not been static in traditional Forth, and some of
the restrictions on its usage stem from there. Moreover, in Gforth #>
refers to the top of a stack of HOLD buffers (managed with <<# and
#>>).

- 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: https://euro.theforth.net/2023
dxf
2024-05-06 02:20:27 UTC
Reply
Permalink
Post by Anton Ertl
...
So your complete setup is
: SHOLD HOLDS ;
: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by Anton Ertl
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
And it works fine. Of course, because it uses <#, it does not work
#12345. <<# #s #67890. <<# #s #> cr type #>> #> cr type #>>
prints
67890
12345
but
#12345. <<# #s #67890. <<# #s #> +comma cr type #>> #> cr type #>>
prints
67,890
*the terminal*:30:49: error: Result out of range
#12345. <<# #s #67890. <<# #s #> +comma cr type >>>#>><<< #> cr type #>>
kernel/nio.fs:63:44: 0 $7FE0F9CB8690 throw
But that could be fixed by using <<# in +COMMA.
Have you documented that use of <## ##> can adversely impact standard forth
code and practices? It was news to me.
Anton Ertl
2024-05-06 17:58:08 UTC
Reply
Permalink
Post by dxf
Post by Anton Ertl
...
So your complete setup is
: SHOLD HOLDS ;
: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by Anton Ertl
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
And it works fine. Of course, because it uses <#, it does not work
...
Post by dxf
Post by Anton Ertl
#12345. <<# #s #67890. <<# #s #> +comma cr type #>> #> cr type #>>
prints
67,890
*the terminal*:30:49: error: Result out of range
#12345. <<# #s #67890. <<# #s #> +comma cr type >>>#>><<< #> cr type #>>
kernel/nio.fs:63:44: 0 $7FE0F9CB8690 throw
But that could be fixed by using <<# in +COMMA.
Have you documented that use of <## ##> can adversely impact standard forth
code and practices? It was news to me.
I assume you mean <<# and #>>. If you use standard code, you do not
use <<# nor #>>, and the code works as specified in the standard. In
the example above, it's the standard word <# (inside the +COMMA) that
adversely affects the usage of the HOLD buffer stack. You can read
the documentation in
<https://gforth.org/manual/Formatted-numeric-output.html>.

- 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: https://euro.theforth.net/2023
dxf
2024-05-07 02:50:45 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
Post by Anton Ertl
...
So your complete setup is
: SHOLD HOLDS ;
: SPLIT ( a u c -- a2 u2 a3 u3 ) \ split at char
Post by Anton Ertl
r 2dup r> scan 2swap 2 pick - ;
: \CHAR ( a u -- a2 u2 c ) \ extract char from end
: DIGIT? ( char -- flag ) \ true if char is decimal digit
[char] 0 - #10 u< ;
\ Add commas to integer/float numeric string. Uses HOLD buffer
: +COMMA ( a1 u1 -- a2 u2 )
<# [char] . split 2swap shold
0 begin over while >r \char
r> 2dup 3 = swap digit? and
if [char] , hold drop 0 then
swap hold 1+
repeat drop #> ;
And it works fine. Of course, because it uses <#, it does not work
...
Post by dxf
Post by Anton Ertl
#12345. <<# #s #67890. <<# #s #> +comma cr type #>> #> cr type #>>
prints
67,890
*the terminal*:30:49: error: Result out of range
#12345. <<# #s #67890. <<# #s #> +comma cr type >>>#>><<< #> cr type #>>
kernel/nio.fs:63:44: 0 $7FE0F9CB8690 throw
But that could be fixed by using <<# in +COMMA.
Have you documented that use of <## ##> can adversely impact standard forth
code and practices? It was news to me.
I assume you mean <<# and #>>. If you use standard code, you do not
use <<# nor #>>, and the code works as specified in the standard. In
the example above, it's the standard word <# (inside the +COMMA) that
adversely affects the usage of the HOLD buffer stack.
And it's in support of this concept of a HOLD buffer stack (that doesn't
exist in Standard Forth or any other AFAIK) that Gforth won't provide (.)
et al that's been present on virtually all desktop forths?

ISTM Gforth has a choice to make. It can do it its own thing - or it can
adopt what has been common practice. For it's clear that when there's no
common practice, nor moves towards it, there can't be a Standard.
Anton Ertl
2024-05-07 16:07:11 UTC
Reply
Permalink
Post by dxf
Post by Anton Ertl
I assume you mean <<# and #>>. If you use standard code, you do not
use <<# nor #>>, and the code works as specified in the standard. In
the example above, it's the standard word <# (inside the +COMMA) that
adversely affects the usage of the HOLD buffer stack.
And it's in support of this concept of a HOLD buffer stack (that doesn't
exist in Standard Forth or any other AFAIK) that Gforth won't provide (.)
et al that's been present on virtually all desktop forths?
It certainly is a reason why "(.)" with the meaning you seem have in
mind is not a factor of "." in Gforth.
Post by dxf
ISTM Gforth has a choice to make. It can do it its own thing - or it can
adopt what has been common practice. For it's clear that when there's no
common practice, nor moves towards it, there can't be a Standard.
According to you it is common practice already, and I think someone
has also claimed that words like (.) are used often, not that I have
missed them. If it is common practice, and you want to see it
standardized, make a proposal; documenting the common practice in
systems and programs would be useful to support such a proposal.

I see that in SwiftForth 4.0.0-RC87 there are the following number of
uses:

6 (.)
3 (U.)
3 (D.)
3 (DU.)
0 (U.R)
4 #S
10 #>
10 <#

Not defined: (.R) (D.R) (DU.R)

Mostly indepenently of this, I find figForth's factoring of .-related
words (inherited by Gforth) more elegant than the SwiftForth ones:

fig-Forth (reformatted to be more comparable to SwiftForth):

: D.R
Post by dxf
R SWAP OVER DABS <# #S SIGN #>
R> OVER - SPACES TYPE ;
: D. 0 D.R SPACE ;
: .R >R S->D R> D.R ;
: . S->D D. ;

SwiftForth:

: (D.) ( d -- addr len ) TUCK DABS <# #S ROT SIGN #> ;
: (.) ( n -- addr len ) S>D (D.) ;
: D. ( d -- ) (D.) TYPE SPACE ;
: . ( n -- ) (.) TYPE SPACE ;
: D.R ( d n -- ) >R (D.) R> OVER - SPACES TYPE ;
: .R ( n n -- ) >R (.) R> OVER - SPACES TYPE ;

In the fig-Forth variant you could factor out (D.), but it would be
used only once. Likewise, with a fig-Forth-like factoring, the usage
numbers for the (.)-like words would be somewhat lower.

BTW, wouldn't you recommend that Gforth should do its own thing? At
least that's how I read many of your messages over the years.

- 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: https://euro.theforth.net/2023
dxf
2024-05-08 04:01:46 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
Post by Anton Ertl
I assume you mean <<# and #>>. If you use standard code, you do not
use <<# nor #>>, and the code works as specified in the standard. In
the example above, it's the standard word <# (inside the +COMMA) that
adversely affects the usage of the HOLD buffer stack.
And it's in support of this concept of a HOLD buffer stack (that doesn't
exist in Standard Forth or any other AFAIK) that Gforth won't provide (.)
et al that's been present on virtually all desktop forths?
It certainly is a reason why "(.)" with the meaning you seem have in
mind is not a factor of "." in Gforth.
Post by dxf
ISTM Gforth has a choice to make. It can do it its own thing - or it can
adopt what has been common practice. For it's clear that when there's no
common practice, nor moves towards it, there can't be a Standard.
According to you it is common practice already, and I think someone
has also claimed that words like (.) are used often, not that I have
missed them.
Apparently your users have missed it and sought solutions where they
could find it:

https://www.reddit.com/r/Forth/comments/aq3ik5/is_there_a_way_to_convert_a_number_to_string_with/
Post by Anton Ertl
If it is common practice, and you want to see it
standardized, make a proposal; documenting the common practice in
systems and programs would be useful to support such a proposal.
It's my understanding the Technical Committee has responsibility for
maintaining Standard Forth and keeping it relevant.
Post by Anton Ertl
I see that in SwiftForth 4.0.0-RC87 there are the following number of
6 (.)
3 (U.)
3 (D.)
3 (DU.)
0 (U.R)
4 #S
10 #>
10 <#
Not defined: (.R) (D.R) (DU.R)
Mostly indepenently of this, I find figForth's factoring of .-related
: D.R
Post by dxf
R SWAP OVER DABS <# #S SIGN #>
R> OVER - SPACES TYPE ;
: D. 0 D.R SPACE ;
: .R >R S->D R> D.R ;
: . S->D D. ;
: (D.) ( d -- addr len ) TUCK DABS <# #S ROT SIGN #> ;
: (.) ( n -- addr len ) S>D (D.) ;
: D. ( d -- ) (D.) TYPE SPACE ;
: . ( n -- ) (.) TYPE SPACE ;
: D.R ( d n -- ) >R (D.) R> OVER - SPACES TYPE ;
: .R ( n n -- ) >R (.) R> OVER - SPACES TYPE ;
In the fig-Forth variant you could factor out (D.), but it would be
used only once. Likewise, with a fig-Forth-like factoring, the usage
numbers for the (.)-like words would be somewhat lower.
That ignores the use of number strings in applications. SwiftForth did
the right thing in providing them upfront. From one of my apps:

\ Save settings to file
: !SETTINGS ( -- )
s" [options]" write
s" -s" write send.s @ (.) write
s" -c" write char.s @ (.) write
s" -d" write wspace @ (.) write
cspace @ dup 3 <> and ?dup if
[char] , writechr (.) write
then
s" -t" write tone @ (.) write
s" -o" compress @ 0= and write
s" -p" write punct @ (.) write
s" -l" lsignal @ 0<> and write
s" -u" write volume @ (.) write
writecr ;
Post by Anton Ertl
BTW, wouldn't you recommend that Gforth should do its own thing? At
least that's how I read many of your messages over the years.
Implicit in that is avoiding doing things that I'll later regret :)
Anton Ertl
2024-05-08 07:06:24 UTC
Reply
Permalink
Post by dxf
Post by Anton Ertl
If it is common practice, and you want to see it
standardized, make a proposal; documenting the common practice in
systems and programs would be useful to support such a proposal.
It's my understanding the Technical Committee has responsibility for
maintaining Standard Forth and keeping it relevant.
Apparently nobody inside the committee or outside thinks that "(.)"
etc. are sufficiently important to be added to the standard, otherwise
someone would have made a proposal for them, an option that is open to
everyone.

The committee is not a closed club, either, and we would love to have
more participation there, but the bar is somewhat higher, because
presence at two consecutive meetings is required (this requirement can
be lowered at the discretion of the committee).
Post by dxf
That ignores the use of number strings in applications. SwiftForth did
\ Save settings to file
: !SETTINGS ( -- )
s" [options]" write
[char] , writechr (.) write
then
writecr ;
It seems to me that your system is missing a word like

'outfile-execute' ( ... xt file-id -- ... ) gforth-0.7 "outfile-execute"
execute xt with the output of 'type' etc. redirected to file-id.

With that word you could write !SETTINGS as:

\ Save settings to file
: .SETTINGS ( -- )
." [options]"
." -s" send.s @ .
." -c" char.s @ .
." -d" wspace @ .
cspace @ dup 3 <> and ?dup if
[char] , emit .
then
." -t" tone @ .
." -o" compress @ 0= and type
." -p" punct @ .
." -l" lsignal @ 0<> and type
." -u" volume @ .
cr ;

: !settings ( -- )
['] .settings dxf's-default-file @ outfile-execute ;

This allows you to test .SETTINGS interactively and eliminates the
need for words like WRITE, WRITECHR and WRITECR.

- 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: https://euro.theforth.net/2023
dxf
2024-05-08 10:29:37 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
Post by Anton Ertl
If it is common practice, and you want to see it
standardized, make a proposal; documenting the common practice in
systems and programs would be useful to support such a proposal.
It's my understanding the Technical Committee has responsibility for
maintaining Standard Forth and keeping it relevant.
Apparently nobody inside the committee or outside thinks that "(.)"
etc. are sufficiently important to be added to the standard
Then they need to explain on what basis they didn't follow the Standard
if they believed it was sufficient.
Post by Anton Ertl
Post by dxf
That ignores the use of number strings in applications. SwiftForth did
\ Save settings to file
: !SETTINGS ( -- )
s" [options]" write
[char] , writechr (.) write
then
writecr ;
It seems to me that your system is missing a word like
'outfile-execute' ( ... xt file-id -- ... ) gforth-0.7 "outfile-execute"
execute xt with the output of 'type' etc. redirected to file-id.
\ Save settings to file
: .SETTINGS ( -- )
." [options]"
[char] , emit .
then
cr ;
: !settings ( -- )
This allows you to test .SETTINGS interactively and eliminates the
need for words like WRITE, WRITECHR and WRITECR.
And have it disappear off the screen - of what use is that? Besides,
it's indirect to send to console that which is intended for disk.
Anton Ertl
2024-05-09 14:57:36 UTC
Reply
Permalink
Post by dxf
Post by dxf
\ Save settings to file
: .SETTINGS ( -- )
." [options]"
[char] , emit .
then
cr ;
: !settings ( -- )
This allows you to test .SETTINGS interactively and eliminates the
need for words like WRITE, WRITECHR and WRITECR.
And have it disappear off the screen
The output of .SETTINGS is a single line. You have a screen that
cannot display that and your system does not support scrolling back?

But even if you prefer to work in such a deprived environment, the
advantage that you need just one additional word instead of a whole
bunch is still 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 2023: https://euro.theforth.net/2023
dxf
2024-05-10 00:14:23 UTC
Reply
Permalink
Post by Anton Ertl
Post by dxf
Post by dxf
\ Save settings to file
: .SETTINGS ( -- )
." [options]"
[char] , emit .
then
cr ;
: !settings ( -- )
This allows you to test .SETTINGS interactively and eliminates the
need for words like WRITE, WRITECHR and WRITECR.
And have it disappear off the screen
The output of .SETTINGS is a single line. You have a screen that
cannot display that and your system does not support scrolling back?
But even if you prefer to work in such a deprived environment, the
advantage that you need just one additional word instead of a whole
bunch is still there.
All this assumes one needs to see on screen what goes to disk. That's
exceptional in my experience.

The fact remains forth has separate words for console and disk output:
TYPE and WRITE-FILE. These take adr/len strings as arguments. The
numeric primitive for that is (.) and friends. Gforth uses numeric
primitives to build "." but won't make it available to users to send
directly to disk. Standard Forth isn't much better.
Anton Ertl
2024-05-10 06:31:32 UTC
Reply
Permalink
Post by dxf
Gforth uses numeric
primitives to build "." but won't make it available to users to send
directly to disk.
Which numeric primitives are you referring to? I expect that, because
the reality is that all words that Gforth uses to implement "." are
available to users, you will not answer the question, but do your
usual thing and move the goalposts or make some other unsubstantiated
claim to detract from you inability to support your claim.

- 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: https://euro.theforth.net/2023
minforth
2024-05-10 08:34:10 UTC
Reply
Permalink
Even me, as no regular user of gforth, can inspect the code for . :

Gforth 0.7.9_20200709
Authors: Anton Ertl, Bernd Paysan, Jens Wilke et al., for more type `authors'
Copyright © 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
Type `help' for basic help
see .
: .
s>d d. ; ok
see d.
: d. 0
d.r space ; ok
see d.r
: d.r
r tuck dabs <<# #s rot sign #> r> over - spaces type #>> ; ok
see <<#
: <<#
holdend @ holdptr @ - hold holdptr @ holdend ! ; ok
see #>>
: #>>
holdend @ dup holdbuf-end u>= -11 and throw count bounds holdptr ! holdend ! ; ok
et cetera

Perhaps dxf's problem is only, that he uses DOS memory-mapped screens, perhaps
controlled through BIOS interrupts. But only he could tell.
dxf
2024-05-10 12:33:56 UTC
Reply
Permalink
Post by minforth
...
You agree that underlying Gforth's "." there exists a numeric string.
Post by minforth
Perhaps dxf's problem is only, that he uses DOS memory-mapped screens, perhaps
controlled through BIOS interrupts. But only he could tell.
I don't have any problems. My interest is why forth implementations
(not all) haven't provided numeric string functions. A quick glance
suggests Minforth doesn't have them. Any comment about that?
minforth
2024-05-10 18:08:13 UTC
Reply
Permalink
Post by dxf
Post by minforth
...
You agree that underlying Gforth's "." there exists a numeric string.
Post by minforth
Perhaps dxf's problem is only, that he uses DOS memory-mapped screens, perhaps
controlled through BIOS interrupts. But only he could tell.
I don't have any problems. My interest is why forth implementations
(not all) haven't provided numeric string functions. A quick glance
suggests Minforth doesn't have them. Any comment about that?
Yes. Look again. :-)
David LaRue
2024-05-10 21:54:34 UTC
Reply
Permalink
Post by minforth
Post by dxf
Post by minforth
...
You agree that underlying Gforth's "." there exists a numeric string.
Post by minforth
Perhaps dxf's problem is only, that he uses DOS memory-mapped screens,
perhaps controlled through BIOS interrupts. But only he could tell.
I don't have any problems. My interest is why forth implementations
(not all) haven't provided numeric string functions. A quick glance
suggests Minforth doesn't have them. Any comment about that?
Yes. Look again. :-)
As a lifelong developer, I don't understand people that have heard of and
been given a solution for a problem and yet seem to complain that it isn't
available to them everywhere. If you are a developer you will never let what
hasn't been provided to you to block what can be accomplished by your tools.
Make up any missing tools you may need along the way and carry them proudly
as you build more solutions. You are responsible for providing any 'tools'
that your toolset needs to complete the projects that you take on. That is
why someone, perhaps you, chose to call you a developer and task you with
completing a given project.
dxf
2024-05-11 02:16:24 UTC
Reply
Permalink
Post by David LaRue
...
As a lifelong developer, I don't understand people that have heard of and
been given a solution for a problem and yet seem to complain that it isn't
available to them everywhere. If you are a developer you will never let what
hasn't been provided to you to block what can be accomplished by your tools.
Make up any missing tools you may need along the way and carry them proudly
as you build more solutions. You are responsible for providing any 'tools'
that your toolset needs to complete the projects that you take on. That is
why someone, perhaps you, chose to call you a developer and task you with
completing a given project.
I believe I dealt with this. The 'tools' in this instance are factors of "."
- something every forth has. A forth implementer that doesn't expose factors
he himself has used is effectively saying he doesn't consider them important.
It's what Standard Forth is saying. That position is contradicted if users
find themselves having to build from scratch, tools already present in the
system but inaccessible.
dxf
2024-05-11 01:09:02 UTC
Reply
Permalink
Post by minforth
Post by dxf
Post by minforth
...
You agree that underlying Gforth's "." there exists a numeric string.
Post by minforth
Perhaps dxf's problem is only, that he uses DOS memory-mapped screens, perhaps
controlled through BIOS interrupts. But only he could tell.
I don't have any problems.  My interest is why forth implementations
(not all) haven't provided numeric string functions.  A quick glance
suggests Minforth doesn't have them.  Any comment about that?
Yes. Look again. :-)
Where? I typed WORDS as any user would and saw nothing obvious.
a***@spenarnc.xs4all.nl
2024-05-10 09:49:46 UTC
Reply
Permalink
Post by dxf
Post by Anton Ertl
Post by dxf
Post by dxf
\ Save settings to file
: .SETTINGS ( -- )
." [options]"
[char] , emit .
then
cr ;
: !settings ( -- )
This allows you to test .SETTINGS interactively and eliminates the
need for words like WRITE, WRITECHR and WRITECR.
And have it disappear off the screen
The output of .SETTINGS is a single line. You have a screen that
cannot display that and your system does not support scrolling back?
But even if you prefer to work in such a deprived environment, the
advantage that you need just one additional word instead of a whole
bunch is still there.
All this assumes one needs to see on screen what goes to disk. That's
exceptional in my experience.
TYPE and WRITE-FILE. These take adr/len strings as arguments. The
numeric primitive for that is (.) and friends. Gforth uses numeric
primitives to build "." but won't make it available to users to send
directly to disk. Standard Forth isn't much better.
This may not be so separate (in a Forth I'm familiar with ..)

: TYPE DUP OUT +! 1 WRITE-FILE THROW ;
: ETYPE 2 WRITE-FILE THROW ;
[ and : EMIT DSP@ 1 TYPE DROP ; ]

The 1 and 2 refer to standardout and standarderror (unix).
In windows version they are named STDOUT and STDERR.
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat purring. - the Wise from Antrim -
dxf
2024-05-12 02:16:54 UTC
Reply
Permalink
Post by Anton Ertl
...
The committee is not a closed club, either, and we would love to have
more participation there, but the bar is somewhat higher, because
presence at two consecutive meetings is required (this requirement can
be lowered at the discretion of the committee).
There are TC members whose forth only contains Standard words? There
are TC members who only write Standard programs? That might encourage
someone to participate.

Moore doesn't make announcements, doesn't promise heaven, doesn't ask
for followers or helpers. He simply proceeds with what he sees as right
even if it means going alone. OTOH if one wants nothing to be done -
seek a consensus. That works every time.

Loading...