Post by Anton ErtlPost by Gerry JacksonWhat's wrong with Forth using sprintf apart from its C provenance and
taking quite a lot of Forth code for FP which is irrelevant to those
using a desktop PC
Not for those who would have to write that code.
Once written, which it has been, it can be used by all were it not that
Forthers, in general, don't like using code written by others!
BTW thanks for a factual reply. Much better than snarky responses from
others.
I don't why it need pose a problem for users. All that has to be
provided to sprintf is:
( arg1 arg2 ... argn caddr u -- caddr2 u2 ) where (caddr u) is the
format control string and (caddr2 u2) is the result in the current
output buffer. Args1 to n are any mix of integers, FP, strings and
characters in the left to right order they occur in the control string.
Post by Anton Ertl* It consumes a variable number of arguments, something relatively
unusual in Forth;
That presents a challenge to an implementer and makes it more
interesting. The number of arguments and their type is calculated when
the format string is processed. The order in which they appear can be
handled either by using a deep PICK sanitised by using DEPTH or, as
SwiftForth does, by recursion.
Post by Anton Ertland these arguments are a mix of integer and FP
numbers in arbitrary order, which exacerbates the problem.
Makes it even more interesting. Don't forget double integers and the
fact that FP numbers can be on the data stack or a separate stack. On
the data stack that would be handled during control string processing.
On a separate stack is more difficult as standard Forth lacks FPICK,
FDEPTH, F>R etc but can be handled by copying the number of FP numbers
into a FP array and accessing that array.
Post by Anton Ertl* It has a very complicated and not very intuitive interface (e.g.,
see https://pubs.opengroup.org/onlinepubs/7908799/xsh/fprintf.html),
so it's not particularly attractive to use.
People seem to manage and other languages have adopted the approach.
Post by Anton Ertl* And it still cannot do all the things that Marcel Hendrix asked for.
Forth is distributed as source code and someone with Marcel's skills
could, if he thought it worth the effort, add the extra functionality.
Loooking at Marcel's list:
<Marcel>
Basic problems I have with # based printing is output
to be in HEX or DECIMAL without changing BASE, and safe
against THROWs. There is printing with and without a trailing
space (when appending '.' or ','), and left/right aligning of possibly
negative numbers (print BL where a '+' is expected). And o yeah, every
one of these words should give a string result that can be further processed
with other string words. ( BTW, I use I/O device redirection to memory
for TYPE
and friends for that.)
Yes... What to do if printing in HEX, ligning up decimal points in a column
of ± numbers, +Infinity -NaN etc. in too short fields, interchange
',' and '.', interchange 'E', 'e', 'd', 'D', print with scaling ( 1.1k
instead
of 1.100e3 ), suppressing/adding trailing space, etc.? Of course
it is not possible to catch all these (and more) in a single word,
but is there a collection of words that anticipates all possible
results?
</Marcel>
- Hex & Decimal - Can be done with sprintf without changing BASE.
- THROW safe - execute sprintf via CATCH
- trailing spaces with commas etc - OK with sprintf
- left/right aligning with negative numbers - OK
- BL for a + sign - OK
- string result - OK
- lining up decimal points in too short fields - not in sprintf, but
surely a user problem
- 'E' or 'e' etc - OK
- print with scaling - No
- adding trailing space - OK, either left justified or include spaces in
the control string
Not much there that can't be done with sprintf.
It's worth noting that after starting to tidy up my sprintf I thought
that there must be a better way to do it and came up with a layered scheme.
Layer 0; a buffer providing basic saving of strings with full buffer
overflow checking, multiple buffers. A greatly extended
equivalent of Forth's <# etc. I've used <~ etc instead of <#
Layer 1: uses layer 0, basic operators to format numbers and text e.g.
~i ~u ~id ~ud etc for signed and unsigned (double) integer
conversions
~w for field width. Positive/negative argument for right/left
alignment
~uc ~lc for upper/lower case
~s ~c for strings, characters
Layer 2: basic integer sprintf, calls lower layers. Provides layer 1
functionality with a sprintf control string. Layer 1 operators
can be mixed with sprintf. An addition is that the code
generated by sprintf can be compiled as a colon definition.
Layer 3: full functionality of integer sprintf. Uses lower layers.
Layers 4 and 5 (proposed but not yet implemented), basic and full
sprintf functionality respepctively. Floating point conversions
will probably be done by treating the components of a floating
point numbers as a series of integer and character fields and
calling layer 1 operators.
Layers 0 to 3 are complete, the rest is on the back burner at present.
With such a scheme it should be easy to add extra functionality such as
that on Marcel's list.
With such a scheme a user can compile the as much functionality as
needed, reducung unnecessary bloat.
--
Gerry