Is there an easier way of doing this? End goal is a double number representing centi-secs.
empty decimal
: SPLIT ( a u c -- a2 u2 a3 u3 ) >r 2dup r> scan 2swap 2 pick - ;
: >INT ( adr len -- u ) 0 0 2swap >number 2drop drop ;
: /T ( a u -- $hour $min $sec )
2 0 do [char] : split 2swap dup if 1 /string then loop
2 0 do dup 0= if 2rot 2rot then loop ;
: .T 2swap 2rot cr >int . ." hr " >int . ." min " >int . ." sec " ;
s" 1:2:3" /t .t
s" 02:03" /t .t
s" 03" /t .t
s" 23:59:59" /t .t
s" 0:00:03" /t .t
Not bad. Here's a translation. Hopefully it's equivalent (?)
: split ( a u c -- a2 u2 a3 u3 )
>r 2dup r> scan 2swap 2 pick - ;
: number ( a u -- u ) 0 0 2swap >number 2drop ;
: xx. ( u -- ) 0 <# bl hold # # #> type ;
: tab3. ( h m s -- ) 3 spaces ( tab) rot xx. swap xx. xx. ;
: ts_elms ( a u -- h m s )
2>r 0 0 0 2r> begin
[char] : skip [char] : split dup 0> while
number drop 5 roll drop -rot
repeat 2drop 2drop ;
s" 25" ts_elms tab3. 00 00 25 ok
s" 10:25" ts_elms tab3. 00 10 25 ok
s" 2:10:25" ts_elms tab3. 02 10 25 ok
OTOH some implementations
are just neater and its a matter of finding them!
2>r 0 0 0 2r> begin[..]
/int 5 -roll rot drop dup while [char] : ?skip
repeat 2drop ;
Mr. Fifo - self-proclaimed "Mark Twain of Forth"
- has no idea, that writing Forth code doesn't
mean to move bytes around "Back and Forth"
(where did I see that? Let's see... :D ).
Stack jugglery means wasting CPU cycles for
moving the bytes around - it's contrproductive.
Variables have been invented to be used. They're
useful, if you didn't notice, or if they didn't
tell you that in your college, or wherever.
----
On 20/06/2025 3:36 pm, minforth wrote:
Counter-example: a good number of my apps involve structs, arrays
and signal vectors in heap memory. Stack juggling? Absolutely not.
The code would be unreadable and a nightmare to debug.
Factoring in smaller code portions is often impossible because
you can't always distribute data, that inherently belongs together,
over separate words.
Then why factor, when with using named parameters = locals, the
code is already short, readable, maintainable, and bug-free.
Ask yourself why the Forth Scientific Library makes heavy use of
locals.
Of course things look different with simpler applications.
What you're saying is at the level you program, it hardly matters
whether it's Forth or something else. It's true I have little to
no reason to use floating-point. I did wonder why Julian Noble
persisted with Forth.
Counter-example: a good number of my apps involve structs, arrays
and signal vectors in heap memory. Stack juggling? Absolutely not.
The code would be unreadable and a nightmare to debug.
Factoring in smaller code portions is often impossible because
you can't always distribute data, that inherently belongs together,
over separate words.
Then why factor, when with using named parameters = locals, the
code is already short, readable, maintainable, and bug-free.
Ask yourself why the Forth Scientific Library makes heavy use of
locals.
Of course things look different with simpler applications.
On 20/06/2025 3:36 pm, minforth wrote:
Counter-example: a good number of my apps involve structs, arrays
and signal vectors in heap memory. Stack juggling? Absolutely not.
The code would be unreadable and a nightmare to debug.
Factoring in smaller code portions is often impossible because
you can't always distribute data, that inherently belongs together,
over separate words.
Then why factor, when with using named parameters = locals, the
code is already short, readable, maintainable, and bug-free.
Ask yourself why the Forth Scientific Library makes heavy use of
locals.
Of course things look different with simpler applications.
What you're saying is at the level you program, it hardly matters
whether
it's Forth or something else.
On Fri, 20 Jun 2025 5:36:05 +0000, minforth wrote:
Counter-example: a good number of my apps involve structs, arrays
and signal vectors in heap memory. Stack juggling? Absolutely not.
The code would be unreadable and a nightmare to debug.
Factoring in smaller code portions is often impossible because
you can't always distribute data, that inherently belongs together,
over separate words.
Then why factor, when with using named parameters = locals, the
code is already short, readable, maintainable, and bug-free.
Interesting questions. My experience says that arrays and vectors are
ok, but structs are dangerous, (especially?) when nested. In a 'C'
project that I contribute to, structs arbitrarily glue data together,
and then forwardly defined macros hide the details.
It is impossible to debug this code without tools to decompile/inspect
the source. It is very difficult to change/rearrange/delete struct
fields, because they may be used in other places of the code for a
completely different purpose. The result is that structs only grow
and nobody dares to prune them. The only remedy is to completely
start over.
Ask yourself why the Forth Scientific Library makes heavy use of
locals.
Because the original algorithms do.
Of course things look different with simpler applications.
And then Einstein's famous quote spoils the fun.
-marcel--
You can repair such things by using new stack paradigms. I've added<snip>
several ones, most of 'em inspired by others. E.g
"swap 3OS with TOS" (SPIN, a b c -- c b a)
"DUP 2OS" (STOW, a b -- a a b)
But of course, you have to do the work. If you're incapable or too lazy
to do the work, yeah, then you will find Forth bites you. Note that C is
a very nice language as well. Beats Forth performance wise - so, what's
there not to like :)
So, I made me a small extension to the locals word set. Using your
example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
or likewise for floats, doubles, strings, matrices
: FSPIN { f: a b c == c b a } ;
: DSPIN { d: a b c == c b a } ;
: "SPIN { s: a b c == c b a } ;
: MSPIN { m: a b c == c b a } ;
Code generation and register optimization is the computer's job.
SPIN/STOW or similar microexamples can, of course, be defined quickly
with classic Forth stack juggling too. The power of the extension
becomes more apparent with mixed parameter types and/or more parameters,
and of course, with some non-trivial algorithm to solve.
So, I made me a small extension to the locals word set. Using your
example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
or likewise for floats, doubles, strings, matrices
: FSPIN { f: a b c == c b a } ;
On Sun, 22 Jun 2025 21:27:40 +0000, minforth wrote:
[..]
So, I made me a small extension to the locals word set. Using your
example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
or likewise for floats, doubles, strings, matrices
: FSPIN { f: a b c == c b a } ;
: DSPIN { d: a b c == c b a } ;
: "SPIN { s: a b c == c b a } ;
: MSPIN { m: a b c == c b a } ;
Code generation and register optimization is the computer's job.
SPIN/STOW or similar microexamples can, of course, be defined quickly
with classic Forth stack juggling too. The power of the extension
becomes more apparent with mixed parameter types and/or more parameters,
and of course, with some non-trivial algorithm to solve.
Do you mean your compiler automatically handles/allows combinations
like
... 22e-12 69. A{{ ( F: -- a ) ( D: -- b ) ( M: -- c ) SPIN ...
I found that handling mixed types explodes the code that needs
to be written for a simple compiler like, e.g., Tiny-KISS . It
would be great if that can be automated.
On Mon, 23 Jun 2025 5:40:37 +0000, mhx wrote:
On Sun, 22 Jun 2025 21:27:40 +0000, minforth wrote:I don't know if I got you right, because as previously
[..]
Do you mean your compiler automatically handles/allows combinations
like
... 22e-12 69. A{{ ( F: -- a ) ( D: -- b ) ( M: -- c ) SPIN ...
I found that handling mixed types explodes the code that needs
to be written for a simple compiler like, e.g., Tiny-KISS . It
would be great if that can be automated.
defined, SPIN expects three integers on the data stack.
On Mon, 23 Jun 2025 10:02:44 +0000, minforth wrote:
On Mon, 23 Jun 2025 5:40:37 +0000, mhx wrote:
On Sun, 22 Jun 2025 21:27:40 +0000, minforth wrote:I don't know if I got you right, because as previously
[..]
Do you mean your compiler automatically handles/allows combinations
like
... 22e-12 69. A{{ ( F: -- a ) ( D: -- b ) ( M: -- c ) SPIN ...
I found that handling mixed types explodes the code that needs
to be written for a simple compiler like, e.g., Tiny-KISS . It
would be great if that can be automated.
defined, SPIN expects three integers on the data stack.
I was indeed too hasty. If items are stacked, no type conversion
is needed if they are only reordered. (Reordering needs
no code anyway, as it is a only a memo to the compiler.) The
problems only arise when an cell must be translated to a complex
extended float, or when using floats to initialize an arbitrary
precision matrix.
Do you really support matrix and string type locals? The former
I only do for arbitrary precision, the latter can be handled
with DLOCALS| .
minforth@gmx.net (minforth) writes:
So, I made me a small extension to the locals word set. Using your
example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
What is the advantage of using this extension over the Forth-2012:
: spin {: a b c :} c b a ;
?
On 23-06-2025 23:03, minforth wrote:
On Mon, 23 Jun 2025 5:18:34 +0000, Anton Ertl wrote:
minforth@gmx.net (minforth) writes:
So, I made me a small extension to the locals word set. Using your
example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
What is the advantage of using this extension over the Forth-2012:
: spin {: a b c :} c b a ;
?
Obviously, there is no advantage for such small definitions.
For me, the small syntax extension is a convenience when working
with longer definitions. A bit contrived (:= synonym for TO):
: SOME-APP { a f: b c | temp == n: flag z: freq }
\ inputs: integer a, floats b c
\ uninitialized: float temp
\ outputs: integer flag, complex freq
<: FUNC < ... calc function ... > ;>
\ emulated embedded function using { | xt: func }
< ... calc something ... > := temp
< ... calc other things ... > := freq / basic formula
< ... calc other things ... > := flag
< ... calc correction ... > := freq / better estimation
;
While working on such things, I can focus my eyes on the formulas,
all local values are visible in one place, and I don't have to
worry about tracking the data stack(s) for lost/accumulated items.
As I said, it is nothing spectacular, just helpful. And to my own
eyes, it looks neater. ;-)
And before dxf yowls again: it is still Forth. :o)
Well.. Technically everything written in Forth is Forth. But it is not canonical Forth - because if it were canonical Forth, we would have
covered locals in "Starting Forth" - and we didn't.
Now, let's assume we found we were wrong. But there was a chapter in "Thinking Forth" called "The stylish stack" - not "The stylish locals".
As a matter of fact, it states that "the stack is not an array" -
meaning: not randomly accessible. And what are locals? Right. Randomly accessible.
So, what is this? It's a feeble imitation of C. It's not part of the
original design. Because if it were part of the original design, you
would find out what it means to think differently. This is merely C
thinking. Nothing else. Certainly not Forth thinking.
'Look, Ma - I've solved Forth's biggest problem.' ;-)
No really, I'm not kidding. When done properly Forth actually changes
the way you work. Fundamentally. I explained the sensation at the end of
"Why Choose Forth". I've been able to tackle things I would never have
been to tackle with a C mindset. ( https://youtu.be/MXKZPGzlx14 )
Like I always wanted to do a real programming language - no matter how primitive. Now I've done at least a dozen - and that particular trick
seems to get easier by the day.
And IMHO a lot can be traced back to the very simple principles Forth is based upon - like a stack. Or the triad "Execute-Number-Error". Or the dictionary. But also the lessons from ThinkForth.
You'll also find it in my C work. There are a lot more "small functions"
than in your average C program. It works for me like an "inner API". Not
to mention uBasic/4tH - There are plenty of "one-liners" in my
uBasic/4tH programs.
But that train of thought needs to be maintained - and it can only be maintained by submitting to the very philosophy Forth was built upon. I
feel like if I would give in to locals, I'd be back to being an average
C programmer.
I still do C from time to time - but it's not my prime language. For
this reason - and because I'm often just plain faster when using Forth.
It just results in a better program.
The only thing I can say is, "it works for me". And when I sometimes
view the works of others - especially when resorting to a C style - I
feel like it could work for you as well.
Nine times out of ten one doesn't need the amount of locals which are applied. One doesn't need a 16 line word - at least not when you
actually want to maintain the darn thing. One could tackle the problem
much more elegant.
It's that feeling..
On Mon, 23 Jun 2025 5:18:34 +0000, Anton Ertl wrote:
minforth@gmx.net (minforth) writes:
So, I made me a small extension to the locals word set. Using your >>>example SPIN (abc — cba), I can define it as follows:
: SPIN { a b c == c b a } ; \ no need for additional code before ;
What is the advantage of using this extension over the Forth-2012:
: spin {: a b c :} c b a ;
?
Obviously, there is no advantage for such small definitions.
For me, the small syntax extension is a convenience when working
with longer definitions. A bit contrived (:= synonym for TO):
: SOME-APP { a f: b c | temp == n: flag z: freq }
\ inputs: integer a, floats b c
\ uninitialized: float temp
\ outputs: integer flag, complex freq
<: FUNC < ... calc function ... > ;>
\ emulated embedded function using { | xt: func }
< ... calc something ... > := temp
< ... calc other things ... > := freq / basic formula
< ... calc other things ... > := flag
< ... calc correction ... > := freq / better estimation
;
My philosophy for developing programs is "follow the problem".
That is we a problem to solve (task to do). We need to
understand it, introduce some data structures and specify
needed computation. This is mostly independent from programming
language. When problem is not well understood we need
to do some research. In this experiments may help a lot
and having interactive programming language in useful
(so this is plus of Forth compared to C). Once we have
data structures and know what computation is needed we
need to encode (represent) this in choosen language.
I would say that large scale structure of the program
will be mostly independent of programming language.
There will be differences at small scale, as different
languages have different idioms. "Builtin" features of
language or "standard" libraries may do significant
part of work. Effort of coding may vary widely,
depending how much is supported by the language and
surroundig ecosystem and how much must be newly
coded. Also, debugging features of programming
system affect speed of coding.
Frankly, I do not see how missing language features
can improve design. I mean, there are people who
try to use fancy features when thay are not needed.
But large scale structure of a program should not be
affected by this. And at smaller scale with some
experience it is not hard to avoid unneeded features.
I would say that there are natural way to approach
given problem and usually best program is one that
follows natural way. Now, if problem naturally needs
several interdependent attributes we need to represnt
them in some way. If dependence is naturaly in stack
way, than stack is a good fit. If dependence is not
naturaly in a stack way, using stack may be possible
after some reorganisation. But may experience is
that if a given structure does not naturally appear
after some research, than reorganisation is not
very likely to lead to such structure. And even if
one mananges to tweak program to such structure, it
is not clear if it is a gain. Anyway, there is substantial
number of problem where stack is unlikely to work in
natural way. So how to represnt attributes? If they
are needed only inside a single function, than natural
way is using local variables. One can use globals, but
for variables that are not needed outside a function
this in unnatural. One can use stack juggling, this
works, but IMO is unnatural. One can collect attributes
in a single structure dynamically allocated at
function entry and freed at exit. This works, but
again is unnatural and needs extra code.
You have some point about length of functions. While
pretty small functions using locals are possible, I
have a few longer functions where main reason for keeping
code in one function is because various parts need access
to the same local variables. But I doubt that eliminating
locals and splitting such functions leads to better code:
we get a cluster of function which depend via common
attibutes.
These are my observations as well. It all depends on the problem
that you are facing. Now there are some guys who behave
like self-declared Forth mullahs who shout heresy against
those who don't DUP ROT enough.
I realizad that (fortunately) long ago - actually
Stephen Pelc made me realized that (thanks) - see
the old thread "Vector additon" here:
https://groups.google.com/g/comp.lang.forth/c/m9xy5k5BfkY/m/qoq664B9IygJ
...and in particular this message:
https://groups.google.com/g/comp.lang.forth/c/m9xy5k5BfkY/m/-SIr9AqdiRsJ
Now there are some guys who behave
like self-declared Forth mullahs who shout heresy against
those who don't DUP ROT enough.
Is theirs the Forth philosophy?? Really?? I thought the main
Forth principle was "keep it simple". When stack reordering
is the easier way, do it. When using locals is the easier way,
do it.
The more common complaint is that you use some feature they dislike
(typically locals) when you would otherwise DUP ROT instead.
But aren't 'locals' actually PICK/ROLL in disguise?
Aren't 'locals' actually PICK/ROLL in disguise?
: 3DUP ( a b c -- a b c a b c ) 3 PICK 3 PICK 3 PICK ;
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 502 |
Nodes: | 16 (2 / 14) |
Uptime: | 213:55:56 |
Calls: | 9,878 |
Calls today: | 6 |
Files: | 13,791 |
Messages: | 6,205,407 |