Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

using MISC (post 1987 Forth hardware) opcodes

66 views
Skip to first unread message

Jeff Fox

unread,
Jul 9, 2006, 9:03:57 PM7/9/06
to
In the presentation that I for SVFIG I reviewed some
of the things I had talked about in the past regarding
the optimization of minimal instruction set Forth code. I
presented some numbers from an analysis of code written
over a period of a year. This will be review for many and
new for some but I think there are several significant issues
relating to the use of the instructions in real code and about
which optimization techniques apply.

Smaller code tends to be faster code the five bit opcodes
that manipulate the stack are faster than those that
do memory access including calls and returns, that's
the idea. The following large global optimizations were observed:

An optimization of about 15% was observed in code size
and code speed due to the use of tail recursion. The
reason the number is so large is that the shorter the
length of factored Forth words the greater the increase
in efficiency by saving one call and return. And it is
important to note that the saving of one cell on the
return stack is considered a significant optimization.
With misc code expressed in colorforth Forth words
averaged 1.2 lines of code which made tail recursion
significant.

An optimization of about 15% was observed due to the
use of multiple entry points and muliple exit points for
similar reasons to that observed from the use of
tail recursion. It should also be noted this mechanism
can also save the use of a cell on the return stack. Some
compilers will hide these optimizations rather than expose
them in the source.

A global optimization of about 3% was observed in program
size due to not having to always balance stack use
when stack wrap can be utilized. More signficant is that the
technique provided a local 100% optimization and increase
in resolution in a tight timing loop due to the reduced code
overhead. In other applications in the last year much larger
optimization values were observed using stack wrap.

Other local optimizations include the use of @a+ and !a+
in place of a traditional phrase to achieve a local 800%
speedup improvement and size reduction. The same
style and technique can easily be used in ANS Forth but
because it won't have the advantage of mapping directly
to a five bit opcode so the optimization will not be as
significant. But it does provide a mechanism to exploit
auto-increment addressing modes in an instruction set.

-IF, -WHILE, -UNTIL obsolete quite a long list of
traditional words and provide considerable local
optimization in code size and speed. -IF tends to
be about as important as IF because it is a cheap
and fast bit test and also useful in some math.

Many traditional Forth optimizations don't apply. I used
some of them for years in various projects with little real
value but they can provide some amazing benchmark
hackery. Peep-hole or pin-hole optimization techiques and
register machine and stack in memory optimzations may
not apply at all at times. Some sequences look like they
should optimize away in traditional Forth implementations like:

DUP DROP

Presumably that code would not be written that way in
traditional Forth, but other optimizations done by inlining
macros might easily generate that sequence.

But it may be important to note that it is not the same as null
just as the non-destructive IF is not the same as DUP IF
because DUP is destructive.

On P21 for example:

1 2 3 4 5 6 ( 1 2 3 4 5 6 ) \ bottom of stack is 1 2 3 4
DUP ( 2 3 4 5 6 6 ) \ bottom of stack is 2 3 4 5
DROP ( 5 2 3 4 5 6 ) \ 2 3 4 5 repeats at bottom on drop or !
\ example of spinning the stack backwards

The consequence of this different set of important or applicable
optimizations means that, as Mr. Moore put it, "a different style
of coding drops out" compared to the style he used in Forth
twenty years ago.

People are often confused by the numbers reported for code
density of well written misc code but it is not that hard to
understand. In a recent example:

: DEMO ( n1 n2 -- ) over + dup ;

compiles to a single 18-bit opcode while in many other
systems the four words "over" "+" "dup" ";" might each be
12-bit tokens, or 16-bit words, or 32-bit words, which in turn
reference four routines that might be 8 bytes each or more.
The numbers can get quite large on some Forths.

Opcodes as small tokens also allows their use in tokenized
source. In Aha the source for the code phrase in DEMO would
be two words, one token to designate that the following source
tokens are the same tokens as object code tokens, and one
opcode source token. The same phrase is twelve bytes in ASCII.

I think one should begin with an understanding of the
use of the updated virtual machine MISC instruction set
in generic machineForth coding before grappling with
optimizations for parallel programming in SEAforth.
In this case making assumptions based on experience
with traditional Forth and other architectures may lead
to the wrong conclusions about the use of Forth
MISC opcodes. This tends to be lost on
people who remember Forth from the 70s or 80s.

If everyone already remembered all this correctly as I
keep being told they have then excuse me for reviewing it
again for any possible newbies.

I think it is best to begin with some understanding of what
is considered optimized code in this environment before
progressing to an understanding of parallel programming
techniques, ROM BIOS facilites, compiler facilities, libraries,
front ends, IO, or the electrical characteristics that define
SEAforth.

Much of the Forth code and ideas are dangerously close
to what people are used to in traditional and ANS Forth,
two stacks, words, : ;
DUP DROP OVER IF THEN etc.

But the idea that these opcodes were designed and fine
tuned to be used in a different style of Forth coding than
what fell of of the mapping of traditional Forth to big
desktop chips.

The idea of a sea of small Forth processors is very different
than the idea of hundreds of millions of transistors in one
giant Wintel style processor. And naturally Forth maps
differently to these very different environments.

Bernd Paysan

unread,
Jul 10, 2006, 9:10:59 AM7/10/06
to
Jeff Fox wrote:

Thanks for the overview.

> But it may be important to note that it is not the same as null
> just as the non-destructive IF is not the same as DUP IF
> because DUP is destructive.

Yes, that's obvious. That means you can't use DUP IF if you have a full
stack and want to branch on the top of stack element. That's the up side:
you save one stack element. The cost is that you lose the destructive IF,
and you need to DROP the flags when you don't need them (maybe it's my
programming style, but that's the majority). Finally, on my code, the
coincidence of having a DUP IF and a full stack at the same time was zero,
so I reverted to a destructive IF in the two b16 variants that are used in
our products.

Typical cases of IF in my environment:

( value ) #mask and IF
( value ) dup #mask and IF
( value ) #mask and dup IF

The last version actually can be done with a non-destructive IF, but there
is a free stack entry for DUP IF available.

I'd like to see a useful example where you have a full stack at the
non-destructive IF.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

John Doty

unread,
Jul 10, 2006, 2:09:18 PM7/10/06
to
Bernd Paysan wrote:

> Jeff Fox wrote:
>
> Thanks for the overview.
>
>
>>But it may be important to note that it is not the same as null
>>just as the non-destructive IF is not the same as DUP IF
>>because DUP is destructive.
>
>
> Yes, that's obvious. That means you can't use DUP IF if you have a full
> stack and want to branch on the top of stack element. That's the up side:
> you save one stack element. The cost is that you lose the destructive IF,
> and you need to DROP the flags when you don't need them (maybe it's my
> programming style, but that's the majority). Finally, on my code, the
> coincidence of having a DUP IF and a full stack at the same time was zero,
> so I reverted to a destructive IF in the two b16 variants that are used in
> our products.

Have either of you guys considered a flag *register* rather than a flag
in the stack? I think it has some serious advantages.

1. You don't have to worry about either DUP or DROP of flags: the flag
persists until the next test.

2. Explicit arithmetic with flag values is relatively rare, and
"short-circuit evaluation" is often a good (and more efficient!)
substitute anyway.

3. A persistent flag register makes it easy to return success or failure
up through several levels of code, handling it appropritely at each
level without stack gymnastics.

Nondestructive IF seems to me to fight with the stack data flow: it
leaves the flag blocking your other operands so you're almost always
going to need stack gymnastics immediately after. But the need to reuse
the flag is fairly common in my code, so a register allows me to have my
cake and eat it too. The thing I hardly ever want is a stack of flags:
one at a time is usually enough.

--
---
John Doty, Noqsi Aerospace, Ltd.
---
His diagnosis of the hostility ... reflects the willful blindness of the
invader who assures himself that the natives are only made unfriendly by
some other provocation than his own. -Barbara W. Tuchman

Jerry Avins

unread,
Jul 10, 2006, 2:44:25 PM7/10/06
to
John Doty wrote:

...

> in the stack? I think it has some serious advantages.
>
> 1. You don't have to worry about either DUP or DROP of flags: the flag
> persists until the next test.
>
> 2. Explicit arithmetic with flag values is relatively rare, and
> "short-circuit evaluation" is often a good (and more efficient!)
> substitute anyway.

Worth considering.

> 3. A persistent flag register makes it easy to return success or failure
> up through several levels of code, handling it appropritely at each
> level without stack gymnastics.

No. Considered and rejected. If another level also tests, the flag won't
persist.

> Nondestructive IF seems to me to fight with the stack data flow: it
> leaves the flag blocking your other operands so you're almost always
> going to need stack gymnastics immediately after. But the need to reuse
> the flag is fairly common in my code, so a register allows me to have my
> cake and eat it too. The thing I hardly ever want is a stack of flags:
> one at a time is usually enough.

If I want to mask with the result of > , then it belongs on the stack.
If I want to branch on it, then it's consumed by IF .

Jerry
--
Engineering is the art of making what you want from things you can get.
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

John Doty

unread,
Jul 10, 2006, 3:26:18 PM7/10/06
to
Jerry Avins wrote:

>> 3. A persistent flag register makes it easy to return success or
>> failure up through several levels of code, handling it appropritely at
>> each level without stack gymnastics.
>
>
> No. Considered and rejected. If another level also tests, the flag won't
> persist.

I do this fairly frequently. If you're bailing out of a failure, you
usually do no more tests. Success is occasionally more troublesome, so I
sometimes use an explicit "true" at the tail of a definition to indicate
success. That's less troublesome than stack gymnastics, I think.

>
>> Nondestructive IF seems to me to fight with the stack data flow: it
>> leaves the flag blocking your other operands so you're almost always
>> going to need stack gymnastics immediately after. But the need to
>> reuse the flag is fairly common in my code, so a register allows me to
>> have my cake and eat it too. The thing I hardly ever want is a stack
>> of flags: one at a time is usually enough.
>
>
> If I want to mask with the result of > , then it belongs on the stack.
> If I want to branch on it, then it's consumed by IF .

Masking with the result is not a technique I ever employed even when I
had a Forth that put flags on the stack, so I guess I don't miss it.
Seems like yet another way to be clever at the expense of readability to me.

Jerry Avins

unread,
Jul 10, 2006, 3:41:37 PM7/10/06
to
John Doty wrote:

...

> Masking with the result is not a technique I ever employed even when I
> had a Forth that put flags on the stack, so I guess I don't miss it.
> Seems like yet another way to be clever at the expense of readability to
> me.

Even DUP IF can be seen as clever by one unaccustomed to it. For me,
masking with a flag is a standard idiom.

: >CHAR ( hex_digit -- ASCII_representation ) DUP 9 > 7 AND + 30 + ;

jmdra...@yahoo.com

unread,
Jul 10, 2006, 3:53:48 PM7/10/06
to

The cost/benifit of a destructive/non destructive IF despends on as
well
as influences programming style. Consider this optimized SwiftForth
code Elizabeth posted some time ago.

===================================================
A favorite example is this definition:

: DIGIT ( n -- n ) DUP 9 > IF 7 + THEN [CHAR] 0 + ;

It converts a single digit to its equivalent
character. It optimizes to
(i386 version):

46E89F 9 # EBX CMP 83FB09
46E8A2 46E8AB JLE 0F8E03000000
46E8A8 7 # EBX ADD 83C307
46E8AB 30 # EBX ADD 83C330
46E8AE RET
===================================================

Here's the equivalent in Pentium colorforth.

(version 1)
: digit -10 + -if 58 + ; then 65 + ;

add EAX, -10
jns label
add EAX, 58
ret
label add EAX, 65
ret

Note for "readability" this could be written as:

: ascii0 48 ;
: asciia 64 ;
: digit -10 + -if [ ascii0 10 + ] + ; then [ asciia ] + ;

Same disassembly. (Thanks to Jeff Fox and others
on the colorforth mailing list for helping me with the
disassembly and a few tweaks to the code.)

There are 5 instructions for the SwiftForth version
and 6 for the ColorForth version. The SF version
has a maximum code path of 3 instructions and
the CF version has a max of 2. You can write
a CF version that has the same # instructions
and same max code path as the SF version.

(version 2)
: digit -10 + -if -7 + then 65 + ;

(Again, thanks CF mailing list).

Anyway, all of that to say this. What happens
when you don't have a CMP instruction (like
the SwiftForth Pentium code) and you don't
have a non-destructive -IF?

Note: Per Jeff the F21 would likely pack
these instructions like this:

# - nop nop \ -10 as 21-bit number
9 \ nops for add w/ -number in T
+ jns label \ jns can go in any slot on f21
# + ret x \ x doesn't matter
58 \ "0" +10 +n -10
label # + ret x \ x can be used for something else
65 \ "A" +n -10

This is from version 1. Version 2
wouldn't be used because it packs
into the same number of instructions on
an F21, with a larger max code path.

And while some might consider this a "contrived"
example, remember it didn't come from the
MISC crowd. ;-)

Regards,

John M. Drake

Jeff Fox

unread,
Jul 10, 2006, 10:55:08 PM7/10/06
to
Bernd Paysan wrote:
> The last version actually can be done with a non-destructive IF, but there
> is a free stack entry for DUP IF available.
>
> I'd like to see a useful example where you have a full stack at the
> non-destructive IF.

What happens at the bottom of stack only really matters if you fill
it all the way or spin it. Those are fairly rare things. You noticed
that I listed it as providing only a 3% optimization in the size of
the code generated in this case.

Despite small stacks needing to fill them all the way is rare
and if you do or want to it does make for a complication in
the complexity of the code do take advantage of those things.
But we think it is not as bad as dealing with the complexity
introduced by stacks that can throw errors instead. The
main thing however is just that these kind of stacks can
be faster than stacks in memory.

Jeff Fox

unread,
Jul 10, 2006, 11:23:12 PM7/10/06
to
John Doty wrote:
> Have either of you guys considered a flag *register* rather than a flag
> in the stack? I think it has some serious advantages.

We found that having a stack of registers with flag bits was much more
powerful compared to classic Forth because of the -IF -UNTIL -WHILE
stuff and 2* but I know that you gave up on classic Forth decades ago
for more conventional things like a conventional flag register design.

> 1. You don't have to worry about either DUP or DROP of flags: the flag
> persists until the next test.

You don't have to worry about a stack or Forth if you choose something
else.

> 2. Explicit arithmetic with flag values is relatively rare, and
> "short-circuit evaluation" is often a good (and more efficient!)
> substitute anyway.

We found it was really powerful for math. I suppose explicit
arithmetic
with flag values is very rare when you only have a single flag register
bottleneck design. Then software has to work that way so the
powerful techniques we used in advanced math wouldn't be possible.
I am reporting what quite a few programmers who worked with this
stuff said, these are not just my opinions.

> 3. A persistent flag register makes it easy to return success or failure
> up through several levels of code, handling it appropritely at each
> level without stack gymnastics.

Stackable flags makes it easy to nest flags to make code smaller
and faster and factored in a Forth way to match other Forth stuff.
If you only had one flag register you would have to do what you
say. I guess that means it is easier in that non-Forth context
than doing it in Forth if that is impossible.

Stack gymnastics are always bad. They are an example of poorly
factored Forth, the definition of poorly factored Forth. It is one of
them, unnecessary variable use is obviously another.

> Nondestructive IF seems to me to fight with the stack data flow:

It is pretty much a non-factor, you gain a little, you lose a little.
It really doesn't matter much.

It was mostly a case of Chuck saying that he felt it would be
better if the language reflected what the hardware actually did
more accurately than to have it add a layer of abstraction and
that the hardware 'really wanted' to do non-destructive tests.

And he said it was going to pretty much be a wash.

And after many man years of programming the staff all said
he was right. It really didn't matter much. You have to have
explicit drops, maybe two if you have a non-destruction branch
and want to get rid of the flag.

And that would happen a lot if you could only test all of the
bits at once. You might want to drop it as often as you test
it in that traditional Forth environment.

But with -IF we might have a math routine, or compiler
routine, or control routine that really want non-destructive
tests. The non-destructive branching makes much more
sense when you consider that I always say that -IF is
more important than IF.

Once you add -IF then non-destructive branching is much
more valuable. That probably isn't obvious if you are not
thinking about Forth or remembering what all those programmers
who did this for all those years said about it.

> it leaves the flag blocking your other operands so you're almost always
> going to need stack gymnastics immediately after.

You haven't convinced me.

> But the need to reuse
> the flag is fairly common in my code, so a register allows me to have my
> cake and eat it too.

One flag register. Not a very novel idea.

We get a few thousand pieces of cake and get to eat them too. So
our code doesn't need any gymnastics to deal with a one
flag register bottleneck. Much of what we showed as our
cleverest code used stacked flags beautifully.

Some people don't like clever code. I know that. We did.

> The thing I hardly ever want is a stack of flags:
> one at a time is usually enough.

I know. And I think that opinion goes back to around the time
that I started doing Forth and you stopped. So I am not supprised
that you would hardly ever want something like that. ;-)

Thanks for the questions and opinions just the same.

Bernd Paysan

unread,
Jul 11, 2006, 8:22:35 AM7/11/06
to
jmdra...@yahoo.com wrote:

> (version 2)
> : digit -10 + -if -7 + then 65 + ;
>
> (Again, thanks CF mailing list).

Good example, but slightly missing the point. If you have a destructive -IF,
you would write that

: digit -10 + dup -if -7 + then 65 + ;

and the dup won't destroy anything (since the -10 consumes the same stack
element as the dup after the +). Yes, that's more work to do, but what you
waste here you might gain elsewhere, so it's all about trade-offs, anyway.
And there's no space in the instruction set for both destructive and
non-destructive branches ;-).

Jeff Fox

unread,
Jul 11, 2006, 10:47:57 AM7/11/06
to
Bernd Paysan wrote:
> you would write that
>
> : digit -10 + dup -if -7 + then 65 + ;
>
> and the dup won't destroy anything (since the -10 consumes the same stack
> element as the dup after the +).

That is more code than with a non-destructive -IF, and it is slower.
The point was that a DUP isn't really needed and makes for smaller
and faster code.

And since -IF has been non-destructive for more than fifteen years your
example with all that extra stuff in it might easily confuse people who
might not have remembered all the details of MISC programming from
previous discussions in c.l.f.

It can be optimized a lot by using a ; before the then
that removes a jump that isn't needed, a literal that isn't needed, and

and another + operation which also isn't needed in the -IF path. Whew.

It packs into the same number of words, but isn't so wastefully
inefficient, the -IF path in your example is more than twice as
long as it should be. If it is easy to make the code more than
twice as fast, and it costs nothing it is a good thing.

An introduction to using MISC opcodes should emphasise this
on day one.

If you are writing a short script on a computer with gigs of memory
then a little extra typing or a program being twice as big or twice
as slow as it could be is no big deal. It doesn't matter much in
that kind of scripting.

But the idea in machineForth is that hardware and software can
be minimized to get the maximum performace for cost for the
targeted app. And in that environment you really don't want
code where each layer is twice as big and twice as slow as
it should be.

It takes a little thought and a desire to make the programs
efficient or there is no point at all to small cheap fast efficient
hardware except that it is easy to make bigger more expensive
and slower copies of it. Anyone can make the hardware slower and
the software bigger and slower. Our goal is to make the
hardware and softtware smaller, cheaper, faster, and
easier to program.

jmdra...@yahoo.com

unread,
Jul 11, 2006, 11:06:46 AM7/11/06
to

Bernd Paysan wrote:
> jmdra...@yahoo.com wrote:
>
> > (version 2)
> > : digit -10 + -if -7 + then 65 + ;
> >
> > (Again, thanks CF mailing list).
>
> Good example, but slightly missing the point. If you have a destructive -IF,
> you would write that
>
> : digit -10 + dup -if -7 + then 65 + ;
>
> and the dup won't destroy anything (since the -10 consumes the same stack
> element as the dup after the +). Yes, that's more work to do, but what you
> waste here you might gain elsewhere, so it's all about trade-offs, anyway.
> And there's no space in the instruction set for both destructive and
> non-destructive branches ;-).
>
> --
> Bernd Paysan

Hello Bernd. I didn't "miss" the point. You made two points and I
addressed
one of them. Here's the point I was addressing.

************************************************************************************


The cost is that you lose the destructive IF, and you need to DROP the
flags when you don't need them (maybe it's my programming style, but
that's the majority).

************************************************************************************

On the Pentium you have an actual CMP instruction so it's possible for
SwiftForth to make the type of optimization it does. But most MISC
chips don't have that instruction. This leads to a different coding
style,
at least in this example. That doesn't mean there aren't times you
need to DROP the flag under MISC any more than it means there
aren't times you need to DUP the flag under ANS. But this is just
an example where factors OTHER than whether or not you have
a destructive IF dictates what's more efficient. Of course there are
tradeoffs. Nobody is debating that there aren't.

Regards,

John M. Drake

Elizabeth D Rather

unread,
Jul 11, 2006, 5:45:49 AM7/11/06
to
Jeff Fox wrote:

> ...


> Despite small stacks needing to fill them all the way is rare
> and if you do or want to it does make for a complication in
> the complexity of the code do take advantage of those things.
> But we think it is not as bad as dealing with the complexity
> introduced by stacks that can throw errors instead. The
> main thing however is just that these kind of stacks can
> be faster than stacks in memory.
>

I concur with the general point that Forth stacks don't need to be big.
We've done a few studies on large applications, and the stacks rarely
get deeper than 4-5 items. It's ironic that Forth's stacks are explicit
and obvious, but remain consistently way smaller than C's implicit
stacks. The stacks on the SEAForth chips seem small, but then the whole
chip is small, and one will have to be sensitive to this when
programming it.

I do like being able to detect stack underflows, though. That's very
helpful in catching programming errors. Ideally, of course, one
shouldn't make errors, but none of us is perfect.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310-491-3356
5155 W. Rosecrans Ave. #1018 Fax: +1 310-978-9454
Hawthorne, CA 90250
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================

Marcel Hendrix

unread,
Jul 11, 2006, 6:34:06 PM7/11/06
to
Elizabeth D Rather <econ...@forth.com> writes Re: using MISC (post 1987 Forth hardware) opcodes
[..]

> I concur with the general point that Forth stacks don't need to be big.
> We've done a few studies on large applications, and the stacks rarely
> get deeper than 4-5 items.

Hm.

I tried iForth, SwiftForth, gForth and VFX with the following words
(all on Windows XP):

: w1 S" HELLO" TYPE ; TEST w1
: w2 123.123e-12 F. ; TEST w2
( w3 ) TEST WORDS
( w4 ) TEST CREATE aap

Approximate number of return stack cells needed for ...

word iForth SwiftForth gForth VFX
------+------------------------------------
w1 2 42 1 10
w2 6 49 4 21
w3 7 126 2 4
w4 9 75 8 8
------+------------------------------------

Wow, there is some pretty fine-grained factoring going on
in SwiftForth :-)

Maybe my stack trick doesn't work for your company's Forth.
What would be your own results for these words?

In a distant past, Coos Haak independently wrote a depth checker.
He might be able to crosscheck some of these results.

-marcel

-- -----------------------------------------------------------
0 [IF]
This utility assumes that stacks grow down.
This utility assumes that stacks are at least 130 cells deep.
This utility is not very accurate for shallow programs (words).
[THEN]

0 VALUE deep130
0 VALUE rminimum

: @+ DUP CELL+ SWAP @ ;

0 VALUE s^
CREATE s-stack 256 CELLS ALLOT

: >S s^ 1+ $FF AND DUP TO s^ CELLS s-stack + ! ;
: -S s^ 1- $FF AND TO s^ ;
: S s^ CELLS s-stack + @ ;
: S> S -S ;

\ This word writes the same address all over the return stack
: MARK-130 deep130 130 < IF deep130 1+ TO deep130
RECURSE
THEN ;

\ This word serves to find out how many levels TEST itself will use.

: CALIBRATE 0 LOCALS| lowraddr |
0 TO deep130
['] NOOP >S
RP@ 130 CELLS - TO lowraddr
MARK-130 S> EXECUTE
lowraddr DUP @ >S
130 0 DO @+ S <> IF LEAVE THEN LOOP -S ( addr)
lowraddr 130 CELLS + SWAP - 1 CELLS / TO rminimum ;

CALIBRATE

: FILL-DATA ( -- )
100 0 DO -2 -2 >S LOOP
100 0 DO DROP -S LOOP ;

: TEST 0 0 0 LOCALS| lowraddr | \ <?> TEST #<name># --> <?>
0 TO deep130
' ( token) >S
RP@ 130 CELLS - TO lowraddr
MARK-130 FILL-DATA S> EXECUTE

lowraddr DUP @ >S
130 0 DO @+ S <> IF LEAVE THEN LOOP -S ( addr)
lowraddr 130 CELLS + SWAP - 1 CELLS / rminimum -
CR ." Approximately " . ." Rstack cells used." ;

: .ABOUT CR ." TEST <word> finds out how many stack cells <word> uses."
CR ." Example: TEST CR "
CR ." The accuracy is rather low for `shallow' words." ;

.ABOUT CR

Elizabeth D Rather

unread,
Jul 11, 2006, 6:54:23 PM7/11/06
to

What's going on here is that W1 and W2 do output, which requires Windows
calls. Windows calls use buckets of stack, because it's C-ish rather
than Forth-ish. My good results are from standalone Forth apps. That's
an appropriate comparison when the size of SEAForth stacks is at issue.

We've actually done some applications on 8051 versions with on-chip
stacks which are pretty small.

Adam Warner

unread,
Jul 12, 2006, 5:51:37 AM7/12/06
to
On Mon, 10 Jul 2006 19:55:08 -0700, Jeff Fox wrote:

> What happens at the bottom of stack only really matters if you fill it
> all the way or spin it. Those are fairly rare things. You noticed that
> I listed it as providing only a 3% optimization in the size of the code
> generated in this case.
>
> Despite small stacks needing to fill them all the way is rare and if you
> do or want to it does make for a complication in the complexity of the
> code do take advantage of those things. But we think it is not as bad as
> dealing with the complexity introduced by stacks that can throw errors
> instead. The main thing however is just that these kind of stacks can be
> faster than stacks in memory.

And elsewhere in this thread you write, "Our goal is to make the hardware
and software smaller, cheaper, faster, and easier to program." I don't see
a conceptual foundation for the claim this hardware/software combination
is easier to program.

On the contrary I see no support for Forth's primary abstract data type:
the stack. Non-tail recursion will very quickly use up the six or so free
slots in "these kinds of stacks" before wrapping around and corrupting
data. If this hardware/software combination has no effective support for
non-tail recursion it will be less expressive and harder to program for
than hardware and software with support for large stacks.

So what is the abstract data type driving this programming model? If one
depends upon the semantics of pushing/popping a wrap-around bank of slots
then code will be tied to the specific number of slots implemented by the
hardware. Such code will break if the number of slots is ever increased,
and this is bound to occur in future revisions of hardware.

In other words you're writing assembly code! What is the higher level
language that is easier to program for that generates code for this CPU?
And how is this hardware a good fit for that higher level language?

You've already described how a DUP DROP combination cannot be optimised
away because DUP is destructive. In an abstract programming model it
should be a conceptual no-op and a compiler will be required to make DUP
appear non-destructive by handling slot spills instead of corrupting other
slots. This sounds a lot like the handling of register spills by compilers
for register machines.

You may be able to make the case for a new programming model based upon a
different abstract data type and virtual machine that is arguably superior
to the Forth two-stack virtual machine.

Regards,
Adam

George Hubert

unread,
Jul 12, 2006, 6:57:11 AM7/12/06
to

Marcel Hendrix wrote:
> Elizabeth D Rather <econ...@forth.com> writes Re: using MISC (post 1987 Forth hardware) opcodes
> [..]
> > I concur with the general point that Forth stacks don't need to be big.
> > We've done a few studies on large applications, and the stacks rarely
> > get deeper than 4-5 items.
>
> Hm.
>
> I tried iForth, SwiftForth, gForth and VFX with the following words
> (all on Windows XP):
>
> : w1 S" HELLO" TYPE ; TEST w1
> : w2 123.123e-12 F. ; TEST w2
> ( w3 ) TEST WORDS
> ( w4 ) TEST CREATE aap
>
> Approximate number of return stack cells needed for ...
>
> word iForth SwiftForth gForth VFX
> ------+------------------------------------
> w1 2 42 1 10
> w2 6 49 4 21
> w3 7 126 2 4
> w4 9 75 8 8
> ------+------------------------------------
>

For W32F V6.11.09 I get

w1 1
w2 77
w3 97
w4 11

w2 and w3 both take so many cells because they both use a local buffer
which is on the rack. Curiously noop (which simply does next) reports 1
cell used, even though none are! I also noticed that 2 zeroes are left
on the stack after the testing.

> Wow, there is some pretty fine-grained factoring going on
> in SwiftForth :-)
>
> Maybe my stack trick doesn't work for your company's Forth.
> What would be your own results for these words?
>
> In a distant past, Coos Haak independently wrote a depth checker.
> He might be able to crosscheck some of these results.
>
> -marcel
>

George Hubert

Brad Eckert

unread,
Jul 12, 2006, 11:10:38 AM7/12/06
to

Adam Warner wrote:
>
> And elsewhere in this thread you write, "Our goal is to make the hardware
> and software smaller, cheaper, faster, and easier to program." I don't see
> a conceptual foundation for the claim this hardware/software combination
> is easier to program.
>
I think this assertion relates to the psychology of Forth programming.
Their version of Forth takes the "virtual" out of VM. colorForth code
on a C18 is written to the C18's restrictions and strengths. It has few
keywords to remember and the set of words that are opcodes is small and
simple. Your restrictions are real hardware, not an abstract model.
It's not ANS so you don't treat it like ANS. Maybe that's why Jeff says
it's "Easier to program". That's not to say it can't be portable. You
can build a portable app on top of a non-portable harness layer, or if
for some reason the C18 isn't available in the future you can make a
slow one with programmable logic.

And here I am still using ANS Forth. If I want a colorForth feature I
kludge it up with some non-portable code.

Brad

Bernd Paysan

unread,
Jul 12, 2006, 11:15:17 AM7/12/06
to
jmdra...@yahoo.com wrote:
> Hello Bernd. I didn't "miss" the point. You made two points and I
> addressed one of them. Here's the point I was addressing.

I was looking for an example where the non-destructive IF is essential,
because you'd use up one more stack element with a destructive "dup IF"
sequence.

It's obvious that this example is better with a non-destructive IF. This is
just tradeoff stuff, where you can say "my code has more "dup IF"s than
non-dup IFs, so the non-destructive IF is better" or it's the other way
round, and then the destructive IF is better - it just depends on your
code.

Jeff Fox argued that using the non-destructive IF is more than just a
trade-off between the frequency of "dup IF"s vs. non-dup IFs, since you can
save one stack item if you have that non-destructive IF.

I did implement the non-destructive IF in the first b16, to check out how
well this works. It didn't. The pattern started to look like

IF drop ... dup THEN drop

and that was the end of the non-destructive IF.

I also have a version of SIEVE to compare: One with non-destructive IF:

: wfill ( n addr u -- ) over >a + com
BEGIN over a!+ dup a + drop cUNTIL drop drop ;
: sieve ( -- n )
$0101 # $100 # 8192 # wfill
$100 # 8192 # over >a + com 2 # 0 # >r
BEGIN
ac@+ IF r> + >r a >r
BEGIN dup a + >a over a + drop -cWHILE
0 # ac!+ AGAIN THEN
r> >a dup THEN drop
2 # + over a + drop cUNTIL
drop drop r> ;

Note that the carry flag in my b16 is a traditional carry flag (unlike
Chuck's carry flag), so I could use drop cbranch. This actually *has* one
place where the non-destructive IF is used!

And the one with destructive IF:

: wfill ( n addr u -- ) over >a + com
BEGIN over a!+ dup a + cUNTIL drop drop ;
: sieve ( -- n )
$0101 # $100 # 8192 # wfill
$100 # 8192 # over >a + com 2 # 0 # >r
BEGIN
ac@+ IF r> 1 # + >r a >r
BEGIN dup a + >a over a + -cWHILE
0 # ac!+ AGAIN THEN
r> >a THEN
2 # + over a + cUNTIL
drop drop r> ;

Jeff Fox

unread,
Jul 12, 2006, 12:50:45 PM7/12/06
to
Adam Warner wrote:
> And elsewhere in this thread you write, "Our goal is to make the hardware
> and software smaller, cheaper, faster, and easier to program." I don't see
> a conceptual foundation for the claim this hardware/software combination
> is easier to program.

The documentation goes back almost twenty years. If you have been
following it you have seen the explanations of the conceptional
foundation for each of the changes introduced. Because much of
it is ancient history now probably the only place you will find it is
in the old pages at my site that document that fifteen year period
where Dr. Ting and I wrote the only documentation.

Take the removal of ELSE for instance.

This clearly had nothing to do with hardware in that an ELSE is
just a jump and the machines all have had jump instructions.

Like dozens of other things Chuck explained his reasoning.

People had experimented with factoring Forth code many different
ways and there were many debates about favoring using ; or
facoring using IF ELSE THEN or IF THEN or nested IFs and
BEGINs and FORs and DOs and CASE and RECURSE etc.

He concluded that he wanted to enforce a higher degree of
factoring than he saw in other people's code where their
definitions didn't use ; factoring very much. I can think of
many people who have posted Forth defintions in c.l.f that
had 100 lines between semicolons and deeply nested
IF BEGIN DO constructs between the : and ;

This looked very much like the C code from which it was
copied, but it never looked like good Forth to Chuck who
felt that more factoring into Forth words was better.

And the idea of Forth chips was to make things that are
good to Forth, less of a penalty to encouage their use.
So calls and returns were emphasized as were all the
other Forth primitives. The idea was that people were
writing unreadable page long Forth words perhaps
because they were afraid of the overhead of using : ;
on some architecture, or because they were copying C,
or because it was their habit to only nest IFs 7
levels deep and DOs 7 levels deep inside of a single
definition

So instead of using ELSE, Chuck wanted to use ; instead.

This would keep words short and simple as in:

: DEMO blah if this ; then that ;

Chuck said, for those interested in the conceptual foundation
for why he removede ELSE, that this would enforce factoring
into smaller definitions and make the code easer to write,
to read, and to maintain.

He said, if you make your code that simple that most of the errors
that happen to people in the page long definitions, that are so
popular in c.l.f, would not happen. He said if you use that kind
of simple one liner definitions and test them that most of the
errors that other people see will be impossible.

And for those interested in the conceptual foundation we followed
through reporting that this had indeed had the effect that Chuck
had hoped. Forth code with short defintions is easier to read,
easier to write, and easier to maintain.

And pretty much everyone in Forth seems to agree with that
last sentance. The problem is that there is no hard definition
for short. I hear people say, I write short words in Forth
they use usually less than one page. I see a lot of 100
line Forth words in c.l.f along with people saying that short
definitions are good things.

This is why I added that in measurements I made over a year
words averaged 1.2 40 character lines in Lenght, and the
typical word was the size of DEMO above or smaller.

There are about 20 things like that that explain the reasoning
why things were done the way they were done in the last
twenty years by the inventor of Forth to try to improve the
language and make Forth more Forth-like. And the 20
things over 20 years are all documented and explained.

But when people skip over the hows and whys and
look at what appears to be more or less the same old
Forth instruction set, and they don't appreciate how the
instructions work with one another, how one puts them together,
how the compiler works, how the code is intended to be
written to make Forth work better they are easily confused.

And if they read c.l.f where 90% of what is written about
this is confusion and guesses they are likely to be very
confused.

We say, we did this particular thing to de-emphasis
JUMPs and emphasis proper Forth factoring yet
people ask why we 'emphasise jumps.'

We say that we emphasise the use of the stack but
people ask why we de-emphasis the use of the stack.

We say that we want to encourage the use of Forth by
showing how the code can be made smaller, faster,
easier to read and write and maintain, and at the same
time the hardware can be made smaller and faster
and cheaper if both work together nicely in a Forth way.
And we say, if you want C hardware and C software
then this doesn't apply to you. We are talking Forth.

And I like to remind people that the opinion of most of
the programmers who have done the 100 man years of work
using this stuff have said that Chuck was right in his
conceptual foundataion and that the optimizations did
increase their productivity. But of the people with that
100 man years of experience I am about the only one
who posts in c.l.f. And for the most part those who
do post about things like the MISC instruction set
have at most a few hours or a few days exposure
and have been exposed to 90% wrong guesses anyway
and that is mostly what they remember.

> On the contrary I see no support for Forth's primary abstract data type:
> the stack.

Forth is about words, and words need a stack so most of Forth
words manipulate the stack.

I am at a complete loss to understand how you can't see that
Forth needs stacks.

> Non-tail recursion will very quickly use up the six or so free
> slots in "these kinds of stacks" before wrapping around and corrupting
> data.

P21 only had 4 levels on the return stack. My old fashioned style
Forth didn't fit well. And I wrote an ANS Forth. In fact I wrote
about 30
to compare.

And I learned more about what Chuck thought was 'good' Forth and
realized that one of the big differences was that because my code
was not well thought out or well factored it was wasteful and easily
used up resources without doing much. But I learned what
Chuck had meant when he said that he had put in about all that
was really needed for good Forth code.

You have to understand the conceptual foundatation about how
Forth code should be constructed and factored. And people do
get confused about how code can have short words and lots
of : and ; and also use a minimal amount of the stacks!
It is no different than people having trouble understanding how
someone can balance on a bicycle, once they learn to do it
they do it by reflex and it is easy. If you have never done it
it might look hard. And some people try it, fall off, and decide it
is hard and never try again. So we see page long Forth words.

> If this hardware/software combination has no effective support for
> non-tail recursion it will be less expressive and harder to program for
> than hardware and software with support for large stacks.
>
> So what is the abstract data type driving this programming model? If one
> depends upon the semantics of pushing/popping

pushing and poping is what you do at the top of a stack
that use is what defines them as stacks
stacks are not infinte, they are finite
what goes on at the bottom is optional, wrap or error throwing hardware

> a wrap-around bank of slots
> then code will be tied to the specific number of slots implemented by the
> hardware. Such code will break if the number of slots is ever increased,
> and this is bound to occur in future revisions of hardware.

ok, more conceptual foundation review:

P21 had 3 and 6 and F21 had 18 and others have had different stack
depths and it has not been a problem.

Stack depths are configurable in most Forths and it is not a big deal.
it is called an environmental dependency in ANS language.

> In other words you're writing assembly code!

ok, more conceptual foundation review:

Yes. We have created a Forth that is also assembler.

This eliminates the need for an assembler vocabular and separate
function that makes Forth a lot simpler and easier.

This makes the operation of the optimziing compiler straighforward
so we have the isomorphic properties of old fashion threaded
Forth that are what still have some people using those 35 year
old Forths. They don't have the complications imposed by
optimzing compilers that produce code that doesn't directly
match up against the source code, which are not easily
manipulated in a mechanical fashion, and which may
complicate debugging problems introduced by hidden
optimizations.

So we get the added benefit that the compiler is also made
simpler and smaller and faster.

I find it interesting to read things Chuck wrote about Forth
ten years before I met him. He was explaining this stuff 30
years ago and I sure didn't get it then. I felt that I began to
get it fifteen years ago and began trying to document it.
Chuck said that he thought I got it and that I did a better
job of documenting it than he. And he encouraged me to
document it.

Some people have hated that I documented it. But I still
try to answer people's questions when they ask.

> What is the higher level
> language that is easier to program for that generates code for this CPU?

Forth. Classic Forth with some enhancements in the last twenty years
called machineForth and some in the last ten years called colorforth.
And we have had variants for parallel programming as well that are
other variants of Forth. Forth.

> And how is this hardware a good fit for that higher level language?

ok, more conceptual foundation review:

The compiler is simpler, smaller and easier to understand.
The generated code is simpler, smaller, and easier to understand.
There is no extra assembler languge.
There is no underlying foriegn architecture to understand or map to
Forth.
The mapping is direct and simple.
The generated code is easy to debug.
The generated code is easy to manipulate.
Those are the advatages of classic threaded Forth, combined with
the advantages of assembler, combined with the advantages of
optimizing compilers, and yet when combines still simpler than
any single one of them in a conventional system.

We usually have the shortest source.
We usually have the least object code.
We sometimes lose on speed on things we want to do to
chips that cost hundreds of times more.
We sometimes beat those chips by a huge margin on things
we want to do.
We don't try to compete for Windows or FP apps.
But we have clearly demonstrated shorter, simpler, and faster
code, au nausium for many years. And I often repeat the
explantations for those who have somehow missed the
megabytes of explanations of the conceptual foundation
in the past and want it again in c.l.f.

> You've already described how a DUP DROP combination cannot be optimised
> away because DUP is destructive.

ok, review:

I can when you don't care about the bottom of the stack. But if you
are using the whole stack then you can't optimize it away, because
it is an optimization already.

> In an abstract programming model it
> should be a conceptual no-op and a compiler will be required to make DUP
> appear non-destructive by handling slot spills

What is a slot spill?

We have four slots for opcodes in an instruction word.

> instead of corrupting other slots.

Every item written to any stack overwrites something. period.
There is no system in which that doesn't happen.

> This sounds a lot like the handling of register spills by compilers
> for register machines.

I realize that many people try to understand Forth in the context of
compilers for register machines. You really can't understand what
we are doing however that way as it is completely different than
that. That is the whole point. It is completely different than that.

> You may be able to make the case for a new programming model based upon a
> different abstract data type and virtual machine that is arguably superior
> to the Forth two-stack virtual machine.

The inventor of Forth said that he has been making improvements to
the language and to the underlying virtual machine since he invented
the language. He has provided a conceptual foundation and
explaination for each of the improvements.

Some people heard about his Forth 35 years ago and made copies.
And people made copies of the copies. And 40,000 people joined
FIG and made a standard of the copies of the copies. And people
followed those standards and modified them for standards from
the late 70s, early 80s, and staring in the mid 80s.

And many quit paying attention to the step by step improvements
the the inventor of Forth was explaining for thrity years and then
said, "I have been doing Forth for 30 years and know all about it,
and I don't know what this guy is doing, but it isn't Forth!" ;-)

I think it is funny that so many people in c.l.f say that they
know so much about Forth that they know that the inventor
of Forth isn't doing Forth, doesn't understand Forth, doesn't
know what Forth word is, doesn't know what a stack is,
and simply doesn't understand programming or computers.
;-)

Sure he "may" be able to "make the case" for some
"new programming model" based on a "different abstract
data type" and a "virtual machine", that isn't the Forth
virtual machine, and then conceivably "argue" with you,
that it is "somehow" (since you doubt it) superior to Forth
but to do that they would have to accept your expert
opinion that it isn't Forth in the first place. That's very
gracious of you. ;-)

Perhaps you should write to Mr. Moore and tell him about his
Forth langauage that he should consider instead of "whatever
thing he is chasing down at the moment" instead of your
language, Forth. ;-)

Maybe he hasn't heard about this langauge that you invented
called Forth. ;-)

Andrew Haley

unread,
Jul 12, 2006, 1:09:53 PM7/12/06
to
Jeff Fox <f...@ultratechnology.com> wrote:
> I think it is funny that so many people in c.l.f say that they
> know so much about Forth that they know that the inventor
> of Forth isn't doing Forth, doesn't understand Forth, doesn't
> know what Forth word is, doesn't know what a stack is,
> and simply doesn't understand programming or computers.
> ;-)

Please provide an example of someone in c.l.f. saying that. It might
be that I missed their posting.

Andrew.

Jeff Fox

unread,
Jul 12, 2006, 1:11:54 PM7/12/06
to
Brad Eckert wrote:
> It's not ANS so you don't treat it like ANS. Maybe that's why Jeff says
> it's "Easier to program".

Another reason is that I have some experience that most in c.l.f don't
have, being around, involved with, or managing 100 man years of work
in ANS Forth and machineforth and colorforth side by side, and
moving between then and keeping track of how long it takes people
to get their programming jobs done in these different environments
in the real world. Other people can guess.

I form my opions on actual experince on a large body of data.
These things are not really all that hard to measure. But proof
is in the mind's eye. And other people are often not willing
to believe someone else's account and want to see the
direct evidence themselves.

But spending ten minutes looking at it and making an abstract
judgement, or spending two days, or two weeks, will not in
my opinion allow one to work out what was worked out and
shown the 100 man years of work that I refer to.

Other people may want to just dismiss this as anecdotal
evidence, and it is. But is nice to be able to report actual
results from actual test and actual comparisons on real
work on real projects and tracked for cost and productivity.
When I report it to others they may dismiss it as anecdotal,
just as they often do other accounts from the real world,
but I think it is more valuable than the guesses in the
absence of any actual facts that prevail in c.l.f.

> That's not to say it can't be portable.

Yes. I think of machineForth as about as portable as ANS.
Sure there are more people who understand and write
code in ANS. But I also know that Chuck thinks portable
means something different than what it means in either
an ANS Forth context or a C context. And I know he
considers machineForth a portable standard. And I know
he lobbied that it had been common practice for a long
time and that much of should have been put into ANS.
But that's history and better put in a different thread.

Pentium colorforth is an indication of just how much lattitude
he thinks one has in implementing the improved 90's style
virtual machine on a target. You have to port a couple K
of machine code for a new processor if it isn't a Forth
processor that already implements this virtual machine
as real hardware.

I have always had the unpopular opinion that since Forth
means porting Forth to so many people that all most
people got out of Pentium colorforth was Pentium details
and they missed the important details, the machineForth
virtual machine, and the colorforth on top. We think of
the Pentium details as the awful but necessary part of
using the PC and once past that focus on Forth.

But other people have spend years looking at the Pentium
details of colorforth without ever figuring out how to add
one to one on the command line of colorforth. To me
that misses the point.

I tend to think using Forth defines Forth and defines an
understanding of Forth. Sure you learn something about
"Forth - the langauge" when you port one, and you learn
about the assembler of some new processors and more
about what a Forth system looks like in code form. And
that's a good 1% intro but many people get stuck there
and never move on.

rickman

unread,
Jul 12, 2006, 1:38:49 PM7/12/06
to
Your post is quite long and I have not finished reading it, but I was
inspired to post a comment. Some time ago you were discussing either
in reply to me or possibly to others that the reason that you don't
*need* complex debugging tools in Forth is because it is written to
deal with problems at a simpler level. I hope I am paraphrasing this
correctly.

Specifically people were complaining that the problem of stack
mishandling required a tool to allow you to observe what the stack is
doing as the code executes, either by single stepping or other means.
Your simple reply was that if you needed such tools, then you can't
count.

At first I thought this was a most absurd point and that of course we
can all count, but we also make mistakes. Yes, we make mistakes, but
the real point is that if you program and debug according to the
methods described as working best for Forth, then you catch bugs like
this at a low level (like the unit test of the word where the mistake
was made) and it really *does* come down to being able to count!

I am not sure why this simple explanation impacted me significantly.
Maybe it was like the time I was learning to program in Lisp and I was
struggling for nearly the whole two weeks we had to learn this language
(it was a whirlwind tour of 6 langugages in one semester). But a
couple of days before our assignment was due something clicked and I
realized how I needed to think in order to make proper use of Lisp! I
finished the assignment in just a few hours and got an A on that unit.


I think with Forth while thinking about your comment I had the
realization that to make the language work so that it is not a bother,
you need to work in smaller chunks so that things like stack usage is
very simple. Of course everyone says to do that, but it just didn't
sink home. I don't think I fully have the hang of it just yet, but I
know the direction I need to head. Somehow the obviously "silly"
statement that we can't count stuck in my head until I understood what
you meant by it.

Jeff Fox wrote:
> : DEMO blah if this ; then that ;

The above is a similar thing. Way back when we used punched cards and
structured programming was a new thing, we were taught that each
routine needed to have only one entry point and one exit. This was a
good idea because it "simplified" the routine and made it easier to set
break points and otherwise observe or predict its behavior. But in
reality we were still making our routines too large! I believe Knuth
said that a routine should fit on a display window which at that time
was 24 lines. Of course we considered this a loose guideline and often
wrote much larger routines. Now I realize that 24 lines is still
overkill for programming in Forth.

I still have trouble with the sheer number of words that an application
ends up with. Maybe I have not had my Lisp-like epiphany for Forth and
am still not factoring correctly. I don't think I am giving up my ELSE
just yet. But I am finally able to put in a requisition for a Forth
tool and will be able to work with it on a project. Then I'll see just
how well I can learn to factor.

Marcel Hendrix

unread,
Jul 12, 2006, 4:38:46 PM7/12/06
to
"George Hubert" <george...@yahoo.co.uk> writes Re: using MISC (post 1987 Forth hardware) opcodes
[..]
> Marcel Hendrix wrote:
[..]

>> Approximate number of return stack cells needed for ...

>> word iForth SwiftForth gForth VFX
>> ------+------------------------------------
>> w1 2 42 1 10
>> w2 6 49 4 21
>> w3 7 126 2 4
>> w4 9 75 8 8
>> ------+------------------------------------
>>

> For W32F V6.11.09 I get

> w1 1
> w2 77
> w3 97
> w4 11

> w2 and w3 both take so many cells because they both use a local buffer
> which is on the rack. Curiously noop (which simply does next) reports 1
> cell used, even though none are! I also noticed that 2 zeroes are left
> on the stack after the testing.

The two zeroes are initializers for locals which were edited out at the
last minute -- make sure you have:

...
: TEST 0 LOCALS| lowraddr | \ <?> TEST #<name># --> <?>
...

I got the following for V6.10.4 ...

V6.11.09 V6.10.04

w1 1 2
w2 77 78
w3 97 83
w4 11 11

-marcel


jeth...@gmail.com

unread,
Jul 12, 2006, 5:06:10 PM7/12/06
to

Jeff Fox wrote:

> Take the removal of ELSE for instance.

> This clearly had nothing to do with hardware in that an ELSE is
> just a jump and the machines all have had jump instructions.

Yes.

> So instead of using ELSE, Chuck wanted to use ; instead.

> This would keep words short and simple as in:

> : DEMO blah if this ; then that ;

This does not make sense to me. What makes this simple is factoring
DEMO into blah this and that.

: DEMO blah if this else that then ;

For ease of use and simplicity for the programmer, I don't see a
difference here -- once the programmer is equally used to both
approaches.

An implementation might make your method compile nicer code without
optimisation. On the other hand, if that's desirable ELSE might be
implemented as

: ELSE POSTPONE ; ; IMMEDIATE

and

: THEN :NONAME POSTPONE THEN ; IMMEDIATE

and depending on your implementation you might get the same result. It
won't work for implementations that leave both colon-sys and dest on
the stack.

Either way, you still have to test every branch of DEMO . And if you
have branches that are hard to factor into THIS and THAT then you can't
do unit tests on THIS and THAT but you have to test DEMO with all its
branches.

It doesn't actually look at all simpler to me. It looks like the same
thing.

> Chuck said, for those interested in the conceptual foundation
> for why he removede ELSE, that this would enforce factoring
> into smaller definitions and make the code easer to write,
> to read, and to maintain.

It's semantic sugar. Since you can implement ELSE in his code with no
trouble (I think)

: ELSE POSTPONE ; :NONAME ; IMMEDIATE

nothing has been enforced.

> He said, if you make your code that simple that most of the errors
> that happen to people in the page long definitions, that are so
> popular in c.l.f, would not happen. He said if you use that kind
> of simple one liner definitions and test them that most of the
> errors that other people see will be impossible.

If you write a page-long definition with one : and a long series of ;
thens, your code is just as complex as the page-long definition with
ELSEs. And no easier to test.

So I think what Chuck is doing here is not enforcing short definitions.
He's suggesting an idiom that might possibly help remind people to
write short definitions. It's like the idea of writing english in E'
where you never use any version of the word "is" or "to be". The
exercise *can* encourage people to think about the times they say one
thing is something else, and so it can have a profound effect on their
thinking. But if they're inclined to use 'is' they're likely to just
replace it with 'seems' or some other formula that fits the same
pattern and then write E' without thinking and lose all the benefit.

It's a reminder. When you choose to use Chuck's Forth you're making a
choice to try for simplicity. And the phrase ; then in place of else
reminds you of that choice.

And that's all it does. it's a subtle trick by Chuck to encourage
people to simplify their code.

I'd be interested to find out I'm wrong about that. Does it actually
make the code easier to debug? Or easier to understand? Easier to
write? If my Forth compiler was arranged so that I could do a global
replace through my code and change every ELSE to ; THEN would my code
be better?

Paul E. Bennett

unread,
Jul 12, 2006, 6:42:46 PM7/12/06
to
rickman wrote:

> ............................................... I believe Knuth


> said that a routine should fit on a display window which at that time
> was 24 lines. Of course we considered this a loose guideline and often
> wrote much larger routines. Now I realize that 24 lines is still
> overkill for programming in Forth.

As one who tends to spread my code, glossary text and other comments over 16
lines for each word I define I would concur. It amazes me that the C
programming crowd in some places where I have worked deal with several
pages of active code for one system function which sports several nested
levels of decision tree. The next, quite similar, function is mostly copied
and pasted with a few tweaks to ensure the correct actions are performed.
very little attempt seems to be made to analyse the code structures for
opportunities to reduce the number of lines of code required.



> I still have trouble with the sheer number of words that an application
> ends up with. Maybe I have not had my Lisp-like epiphany for Forth and
> am still not factoring correctly. I don't think I am giving up my ELSE
> just yet. But I am finally able to put in a requisition for a Forth
> tool and will be able to work with it on a project. Then I'll see just
> how well I can learn to factor.

You probably need to more practice and some others to look over some of your
code and make useful suggestions for improvement. Always possible here or
on the UK-fig mailing list.

--
********************************************************************
Paul E. Bennett ....................<email://p...@amleth.demon.co.uk>
Forth based HIDECS Consultancy .....<http://www.amleth.demon.co.uk/>
Mob: +44 (0)7811-639972
Tel: +44 (0)1235-811095
Going Forth Safely ..... EBA. www.electric-boat-association.org.uk..
********************************************************************

Jeff Fox

unread,
Jul 13, 2006, 12:08:17 AM7/13/06
to
Andrew Haley wrote:
> Please provide an example of someone in c.l.f. saying that. It might
> be that I missed their posting.

Sorry, I should have said, and it happens so often it is probably
happening in another thread or email right now. ;-)

Jeff Fox

unread,
Jul 13, 2006, 12:10:24 AM7/13/06
to
I try to explain that having a stack pointer, and the word depth,
or having hardware to catch hardware stack 'errors' are NOT
the only ways to debug a program or see what is on a stack. :-)
When people say the alternatives are DEPTH and hardware
stack error detect or nothing but buggy programs I think it is
silly.

If they really think that stack depth is such a terrible
unsolvable error trap that it requires these and other words and
all that extra hardware I might try to get their attention by
pointing out that they are just talking about making a simple
counting error! If they stick to simple code the likelyhood of
making a counting error goes down in the first place.

rickman wrote:
> Somehow the obviously "silly" statement that we can't count
> stuck in my head until I understood what you meant by it.

Some people describe that as being bashed over the head. :::-)

The more brutally simple the thing that sticks in their head
the more brutally bashed they may feel.

Thank you.

Andrew Haley

unread,
Jul 13, 2006, 5:28:01 AM7/13/06
to
Jeff Fox <f...@ultratechnology.com> wrote:

> Andrew Haley wrote:
>>Jeff Fox <f...@ultratechnology.com> wrote:
>>> I think it is funny that so many people in c.l.f say that they
>>> know so much about Forth that they know that the inventor
>>> of Forth isn't doing Forth, doesn't understand Forth, doesn't
>>> know what Forth word is, doesn't know what a stack is,
>>> and simply doesn't understand programming or computers.
>>> ;-)
>>

Your claim is that someone on this group has posted, saying that "the
inventor of Forth isn't doing Forth, doesn't understand Forth, know
what Forth word is ..."

I don't believe it.

Look around you. There is a hunger to discover what Chuck is doing,
and where his branch of the tree of Forth systems is going. Not
everybody wants to go down this branch with him, but that doesn't mean
anyone believes that "the inventor of Forth isn't doing Forth, doesn't
understand Forth" or anyone would dream of saying so.

Andrew.

Adam Warner

unread,
Jul 13, 2006, 5:33:54 AM7/13/06
to
On Wed, 12 Jul 2006 09:50:45 -0700, Jeff Fox wrote:

> You have to understand the conceptual foundation about how Forth code


> should be constructed and factored. And people do get confused about how
> code can have short words and lots of : and ; and also use a minimal
> amount of the stacks!

Again, you can only use a bounded amount of stack with tail recursion or
the translation of a recursive definition into an iterative form.

A tail recursive Forth word will call RECURSE as the last thing it does
before exiting the word. A Forth compiler can translate this call into a
jump to the start of the word.

A tail recursive definition is typically harder to write than a non-tail
recursive definition. Here's an example I came up with within the
limitations of my Forth knowledge: Write recursive and tail recursive
words to naively sum the integers from 1 to the first element on the stack.

: non-tail-recursive-sum dup if dup 1- recurse + then ;

This is not tail recursive because + is called after RECURSE before
leaving the word. It is easy to understand because of the recursion:
If the TOS is non-zero, add the TOS to the return value of
non-tail-recursive-sum with input one less than the original TOS.

Here is my tail recursive version. I need to operate upon two input
values, the countdown and sum (which starts at 0), which means I will
need a helper word to first place this 0 on the stack and clean up
afterwards:

: tail-recursive-sum over if over 1- rot rot + recurse then ;
: tail-recursive-sum 0 tail-recursive-sum swap drop ;

Let's step through it to understand how it works (with input 5 and
ignoring the dup for if):
5
5 0
5 0 5 over
5 0 4 1-
4 0 5 rot rot
4 5 +
4 5 4 over
4 5 3 1-
3 4 5 rot rot
3 9 +
3 9 3 over
3 9 2 1-
2 9 3 rot rot
2 12 +
2 12 2 over
2 12 1 1-
1 12 2 rot rot
1 14 +
1 14 1 over
1 14 0 1-
0 14 1 rot rot
0 15 +
15 0 swap
15 drop

I found this tail recursive version much harder to write, and I only
noticed the cleanup after stepping right though it above. A Forth that
supports tail recursion would only use three cells in this case because it
can jump straight back to the start of the definition's code at every
RECURSE.

If your Forth does not have decent sized stacks then you cannot
effectively run recursive definitions, you cannot prototype using
recursive definitions and you will be inhibited from even thinking
recursively. You'll be forced into premature optimisation, writing harder
code for a less expressive Forth.

Regards,
Adam

Mark W. Humphries

unread,
Jul 13, 2006, 6:27:10 AM7/13/06
to
Just about all my looping uses explicit tail recursion, all loops are
factored, no non-tail recursion or any of Forth's traditional looping
words. I suspect I'm not alone practicing this style of coding, I don't
think it results in any real problems.

Jeff Fox

unread,
Jul 13, 2006, 7:04:20 AM7/13/06
to
Andrew Haley wrote:
> I don't believe it.

flamebait

Jeff Fox

unread,
Jul 13, 2006, 7:14:27 AM7/13/06
to
j2th...@cavtel.net wrote:
> Easier to write? If my Forth compiler was arranged so that I could do a global
> replace through my code and change every ELSE to ; THEN would my code
> be better?

I suppose if this were not a thread with the word MISC in the subject
every person in this newgroup would jump in and question your sanity
but if no one else notices the nonsense in this noise let me look at
it.

Global translations, translations in general are not good solutions and
you know that is not our style.

Quite the opposite, it is other folks who want to translate programs
from
one language to another who are on the opposite end of things from
what this thread was about.

Everyone knows that your suggestion to replace all "ELSE" with "; THEN"
would break just about every program in existence.

: SAMPLE DUP 0< IF 2 + ELSE 2 -THEN 2/ ;

every newbie from day one knows that it has two paths after DUP 0< IF

2 + 2/ ;
2 - 2/ ;

Now don't first day newbies in Forth know that

: SAMPLE DUP 0< IF 2 + ; THEN 2 - THEN 2/ ;

is non-standard and is going to throw compiler errors?

Don't they now that one IF and two THENs is bad?

Don't they know that the first ; must be an EXIT in ANS?

Don't they know that EXIT won't work either?

Don't they know that if it did somehow compile that the
two paths would be

2 + ;
2 - 2/ ;

so the first path is now terribly broken?

Is that sort of ridiculous nonsense and noise just tolerated
because you are writing that garbage in a MISC thread.
You have no experience with MISC anyway do you?

Back to your nonsense:
If they had twenty IFs deeply nested in a page long
ANS Forth defintion like we have seen posted to c.l.f
so many times do you really think that replacing all
the "ELSE" with "; THEN" would fix the code?

I have heard some crazy arguments before but that one
is really nuts and is the sort of absurd noise that
keeps people from understanding the most basic things!

Should you replace all "ELSE" with "; THEN" ?why not? ;-)

Jeff Fox

unread,
Jul 13, 2006, 7:22:18 AM7/13/06
to
j2th...@cavtel.net wrote:
> : DEMO blah if this else that then ;

That is a wonderful example of de-optimization.

And you asked why the other syntax is simpler and clearer. ;-)

Your suggestion for alternate syntax adds complexity in five ways:

Simplicity:
There are more different words, IF THEN ; is three different words
IF ELSE THEN ; is four

That is the way it is simpler semantically, 4 vs 3 unique semanitc
terms
and more is more.

Size:
Yours is longer. ELSE adds more characters, more typing, and
bigger is bigger.

Efficiency:

You have a call to THIS
you have a return from THIS
you have a jump
you have a return at the end

So the overhead for THIS is
call, return, jump, return

converting THIS to one call and return makes it twice as small
then converting the call and return to a jump with tail recursion
makes it twice as small again and more.

You have now quadrupled the overhead on THIS

You have a call to THAT
you have a return from that
then you have a then
then you have a return from DEMO

You have doubled the overhead on THAT

And, ... you have used an extra cell on the return stack
as if the return stack were not something that is important
in Forth.

Or, you didn't do all because you have hidden it.

You have made what is going on much harder understand
if you have hidden dozen of details by changing a word
to make it look like what you are used to.

You have done that or just made it bigger, more complex,
slower, less efficent, waste more memory, waste more
stack space, and not be quite as clear as it was.

;-)

Jeff Fox

unread,
Jul 13, 2006, 7:34:25 AM7/13/06
to
j2th...@cavtel.net wrote:
> > Chuck said, for those interested in the conceptual foundation
> > for why he removede ELSE, that this would enforce factoring
> > into smaller definitions and make the code easer to write,
> > to read, and to maintain.
>
> It's semantic sugar. Since you can implement ELSE in his code with no
> trouble (I think)

That's more noise. You are using the term Semantic Sugar
exactly backwards.

We don't have Semantic Sugar. We removed it, you want it.

Or syntax is more explict and clear, not frosting to hide ugliness
or one word hiding a dozen optimizations.

We haven't added a useless word to make it prettier but slow
everything down a lot but make it look 'sweeter' to some people
or hide all the complexity from the programmer to make it
look 'sweeter.'

We did just the opposite.

We removed not added. We simplied not complexified. We
made it more efficient not less.

Shorter, simpler, clearer, and more efficient was the goal and
what we got.

You are the one argueing to add ELSE because to you that
is a sweet. It may look sweet to you but it is fat.

But ELSE is not as horrible as POSTONE :-) and I used it
in the ROM BIOS precisely to avoid using an extra layer
of the return stack to leave more room for application programs
because the use was not like the DEMO example where it is so
obviously a big win in so many different ways.

shorter, simpler, clearer source, and the compiled code it specifies
is shorter, simpler, cleaner, faster, and uses fewer resources,
and it is a much easier way to get that shorter, simpler, faster
object code than with even more elaborate and complex
schemes like using POSTPONE, or totally crazy ideas like
replacing "ELSE" with "; THEN" ;-)

> If you write a page-long definition with one : and a long series of ;
> thens, your code is just as complex as the page-long definition with
> ELSEs. And no easier to test.

You can write as bad of code as you want.
You can brag about the biggest and most bloated code if you want.

People here posts page long defintions with deeply nested
: demo if if if if if if if else if else if else else else if else if
else if if ...
and most of us agree that this cannot be debugged easily. But
it remains popular with some in c.l.f.

We are just saying

: demo if .. ; then ... ;

with only one if per : and no ELSE

is simple enough that no one is going to make the kind of
errors they make with deeply nested IF ELSE THEN DO LOOP
and BEGIN structures going on for a page after a colon.

We are saying we like definitions that are simple and easy to
debug. I think you actually do understand that despite the
silly noise.

Removing ELSE for no reason would be as you say and
people could to and still write page long deeply nested defintitions
that we think are awful. This thread was about using MISC
and I am amazed by the depth of your knowledge.

But if course the point of this thread is one if per : and no ELSE
most of the time which is really a completey different subject
than how to "properly" write page long definitions or how to
"properly" use POSTPONE in ANS.

Jeff Fox

unread,
Jul 13, 2006, 8:15:18 AM7/13/06
to
j2th...@cavtel.net wrote:
> It's like the idea of writing english in E'
> where you never use any version of the word "is" or "to be".

that's nuts. ;-) I am sorry. That nuts.

Hamlet could just say "or not" ;-)

> I'd be interested to find out I'm wrong about that.
> Does it actually make the code easier to debug?

I am reporting the results from 100 man years of work
with the two syntaxes being used side by side.

we say
shorter is shorter
simpler is simpler
smaller is smaller
faster is faster
easier is easier
or more efficient is more efficient
and with small examples they are easy things to see

And yes, when the code is shorter, simpler and clearer
isn't inefficient and doesn't hide important details of what
it is doing it is easier to debug it. ;-)

One thing that attracts people to 30 year old Forths are
the properties of simple threaded code generation that
allowed a lot of simple classic Forth techniques to work.
The simplicity provides isomorphism and simple one to
one correspondence between source and object code
(address lists in those threaded Forths) that made all
the classic things work. It is also why some people
like assembler.

Some people prefer that to the kind of optimizing
compilers for complex chips like Pentium that may
make finding a corespondence between source and
object code more difficult. That kind of optimization
can complicate debugging for some people and they
prefer having somethings that is actually easier to
debug. Or they have to debug with optimization off
and again with optimizations on.

Twenty years ago Mr. Moore reasoned that Forth chips
were too complex and that compilers for Forth chips were
too complex and that a simpler architecture with simpler
code and a simpler compiler would actually be easier
to program and debug. So he began with the idea of
how to simplify the language and make it simpler and
new generations of hardware and compilers followed.
The smallest and simplest compilers followed.
The smallest and simplest hardware followed.

And many programmers at several companies for many
years have used and compared side by side both
standard Forth and MISC and have been in a position
to report results of the 100 man year experiment. Most
avoid c.l.f and special ed classes. ;-)

You have lots of experience with ELSE and no
experience with with this alterntave. So it "looks"
a certain way to you. You obviously don't understand it.

To you it sounds like English with "is" removed. ;-)

Of course you might choose to argue that what that
means all depends on what "is" means. ;-)

But I know you used to do Forth many years ago. I
have heard some funny stories about those days. And
I don't bye that you are as dumb about Forth as you
have pretended to be in in this tread. ;-)

I really can't believe either your stuff about things like
replacing all "ELSE" with "; THEN" using your editor
or that you post that sort of nonsense in a thread
like this and no one else questioned your logic. ;-)
It was hall of fame stuff! ;-)

It is pretty funny though. ;-)

I forget, what language was it that you switched to?
Newspeak? ;-)

Jeff Fox

unread,
Jul 13, 2006, 8:30:27 AM7/13/06
to

Nor do other people who do it.

Chuck went there but went back to using some older flow control
constructs. But he hasn't gone back to ELSE.

jacko

unread,
Jul 13, 2006, 9:39:21 AM7/13/06
to
hi

> Chuck went there but went back to using some older flow control
> constructs. But he hasn't gone back to ELSE.

: ';, ['] ; , ;

: ELSE ';, ['] THEN , ;

but that would mean a new word for every else which was not end
terminal (??)

cheers

jeth...@gmail.com

unread,
Jul 13, 2006, 1:34:08 PM7/13/06
to

Jeff Fox wrote:
> j2th...@cavtel.net wrote:
> > Easier to write? If my Forth compiler was arranged so that I could do a global
> > replace through my code and change every ELSE to ; THEN would my code
> > be better?

> : SAMPLE DUP 0< IF 2 + ELSE 2 -THEN 2/ ;

I see! So how would you do that?

: SAMPLE DUP 0< IF 2 + 2/ ; THEN 2 - 2/ ;

That works, but it duplicates all the code post-split. At least one
extra call, unless there isn't any such code.

: SAMPLE1 IF 2 + ; THEN 2 - ;
: SAMPLE DUP 0< SAMPLE1 2/ ;

That gets rid of the duplication of code but it needs an extra call.

Have I missed something else? I guess it's obvious this is new to me.

rickman

unread,
Jul 13, 2006, 1:52:37 PM7/13/06
to

I don't know about obvious, but it is funny. I remember reading a book
when I was in college about an indian mystic who was teaching a young
college student about their religion and culture. At one point the
indian gives the student a plant which induces halucinations and tells
him to find his "spot" or something like that. The student crawls
around for half the night retching while looking for his "spot" (I
guess drugs were not so good back then). Finally, exhausted, he sits
against a post and falls asleep. In the morning he wakes up and the
indian is congratulating him for finding his "spot".

I think you just did exactly what Jeff is talking about. You factored
the example into two words using the semicolon style. Wasn't the point
that it forces factoring? In fact, couldn't you do this a bit
differently to

: SAMPLE1 IF + ; THEN - ;
: SAMPLE 2 OVER 0< SAMPLE1 2/ ;

I might not have seen this simplification if it had not been broken
into two words. I don't know that this is a good example since it may
not be clear that one solution is better than the other. But I believe
this is the sort of factoring that Jeff is talking about. I am sure
Jeff will let us know.

My problem is that I run out of names for these sort of words.

jeth...@gmail.com

unread,
Jul 13, 2006, 2:51:07 PM7/13/06
to

Jeff Fox wrote:
> j2th...@cavtel.net wrote:
> > : DEMO blah if this else that then ;

> And you asked why the other syntax is simpler and clearer. ;-)

The alternative was

: DEMO blah if this ; then that ;

right?

> Your suggestion for alternate syntax adds complexity in five ways:

> Simplicity:
> There are more different words, IF THEN ; is three different words
> IF ELSE THEN ; is four

I count the body of the definition with 7 words each way.

> That is the way it is simpler semantically, 4 vs 3 unique semanitc
> terms and more is more.

You're saying having one less word in the dictionary is simpler? I'll
go along with that.

> Size:
> Yours is longer. ELSE adds more characters, more typing, and
> bigger is bigger.

Else has more characters than ; , true. It hasn't been a concern for
me, but if it was we could do

: | POSTPONE ELSE ; IMMEDIATE or equivalent. Still it's an extra word
and if we make it shorter that adds *another* extra word.

> Efficiency:

> You have a call to THIS
> you have a return from THIS
> you have a jump
> you have a return at the end

> So the overhead for THIS is
> call, return, jump, return

> converting THIS to one call and return makes it twice as small
> then converting the call and return to a jump with tail recursion
> makes it twice as small again and more.

Ah, tail recursion. That makes sense, and if you're going to do it you
might as well do it explicitly as need an optimising compiler. I
thought you weren't considering that because you said

"Take the removal of ELSE for instance.

"This clearly had nothing to do with hardware in that an ELSE is
just a jump and the machines all have had jump instructions."

But that wasn't what you were talking about.

So with tail recursion you have

Case 1: a nonjump, a call, and a return.
Case 2: a jump, a call, and a return.

While with traditional Forth you have

Case 1: a nonjump, a call, a return, a jump, and another return.
Case 2: a jump, a call, a return, and probably another return. Tail
recursion might be persuaded to remove one of the returns, but it can't
remove the extra Case 1 return without optimisation. The compiler would
have to look ahead to the end of the definition to see whether it could
tail-recurse back at the ELSE .

I remember when I was first learning Forth I looked at the inefficiency
there and thought it was worth it avoid the complications of
unstructuring the code. Or at least it was bearable. I'm glad to see
that getting smoothed out at last.

> You have done that or just made it bigger, more complex,
> slower, less efficent, waste more memory, waste more
> stack space, and not be quite as clear as it was.

Um. I see that it's bigger, because an unconditional jump is bigger
than an exit. That is, not much bigger. But some, and there's no
mechanical value to that unless you have code after the THEN . At that
point you lose the tail recursion and we have to rethink the
efficiency. Still, your code is definitely smaller sometimes.

More complex? I dunno. For the programmer it looks about the same to
me.

A llittle slower, yes. We could get past that with an extra ELSE that
allows tail recursion. But that's yet another extra word when we could
get by eliminating one.

Stack space? You mean return stack, right? I don't much see the
importance. If there's one extra item on the return stack at the
beginning of THIS that will matter if THIS would cause a return stack
overflow, and with one less item it won't. That doesn't look so bad.
But then, if you have commands that nest 12 deep and every one of them
has an unnecessary failure to tail-recurse and an unnecessary return,
that's 24 extra return stack items. Now, the first time I thought about
the possibility of a return stack overflow, I checked my Forth and saw
that it had only 256 items available on the return stack. So I reset a
variable and restarted the Forth, and then it had 1024. I never came
close to a return stack overflow, except when I did recursion that
didn't know when to stop. So I think this problem is only for small
limited Forths. Either because they're so cheap they have limited
memory available, or because they're so fast that they only have
limited on-chip return stack available. It looks like something that
could be worth optimising -- no harm to it ever, and useful sometimes
now when it mostly never mattered before.

Not quite as clear? ELSE makes it structured. Lots of people have
argued that this is clearer. I'm not sure they're right, I think I
could get used to multiple exits easily.

So OK, I'm learning something here. I think this syntax will sometimes
be no more complex, and it can be slightly more efficient, and its
efficiency fits how the machine might actually work.

It's possible to make awful spaghetti code this way, particularly if
you can branch into a named definition. Then you could get things like:

: FOO
test1 if
action1 ;
: BAR
then test2 if
action2 ;
: GLOG
then test3 if
action3 ; then
action4 ;

This might define 3 words or maybe it has some errors. There's nothing
in the ; THEN syntax in itself that promotes short clear code. But it
is better for some machine architectures, and it can be used as a
reminder to write simple clear code.

Paul E. Bennett

unread,
Jul 13, 2006, 3:33:22 PM7/13/06
to
Jeff Fox wrote:

> I try to explain that having a stack pointer, and the word depth,
> or having hardware to catch hardware stack 'errors' are NOT
> the only ways to debug a program or see what is on a stack. :-)
> When people say the alternatives are DEPTH and hardware
> stack error detect or nothing but buggy programs I think it is
> silly.
>
> If they really think that stack depth is such a terrible
> unsolvable error trap that it requires these and other words and
> all that extra hardware I might try to get their attention by
> pointing out that they are just talking about making a simple
> counting error! If they stick to simple code the likelyhood of
> making a counting error goes down in the first place.

While Jeff is right in that it only requires the programmer to keep count of
the items he has on a stack, there are some error scenarios (mostly errant
hardware) that would benefit from advanced warning of stack overflow and
underflows. Why the hardware might be errant may be more to do with cosmic
influences than any fault of design but the High Integrity Systems
Development Community appreciate these little touches when they can be made
available.

Of course, when you have these errors get flagged up you need to deal with
the situation.

jmdra...@yahoo.com

unread,
Jul 13, 2006, 4:34:30 PM7/13/06
to

Andrew Haley wrote:
> Jeff Fox <f...@ultratechnology.com> wrote:
> > Andrew Haley wrote:
> >>Jeff Fox <f...@ultratechnology.com> wrote:
> >>> I think it is funny that so many people in c.l.f say that they
> >>> know so much about Forth that they know that the inventor
> >>> of Forth isn't doing Forth, doesn't understand Forth, doesn't
> >>> know what Forth word is, doesn't know what a stack is,
> >>> and simply doesn't understand programming or computers.
> >>> ;-)
> >>
> >>Please provide an example of someone in c.l.f. saying that. It might
> >>be that I missed their posting.
>
> > Sorry, I should have said, and it happens so often it is probably
> > happening in another thread or email right now. ;-)
>
> Your claim is that someone on this group has posted, saying that "the
> inventor of Forth isn't doing Forth, doesn't understand Forth, know
> what Forth word is ..."
>
> I don't believe it.

Please see:

http://groups.google.com/group/comp.lang.forth/browse_frm/thread/8cd76f7bc05d86c1/b7a9b2b336a2f20f?q=%22it's+not+forth%22&rnum=1#b7a9b2b336a2f20f

There are other examples.

Regards,

John M. Drake

jmdra...@yahoo.com

unread,
Jul 13, 2006, 4:52:01 PM7/13/06
to

j2th...@cavtel.net wrote:
> Jeff Fox wrote:
> > j2th...@cavtel.net wrote:
> > > Easier to write? If my Forth compiler was arranged so that I could do a global
> > > replace through my code and change every ELSE to ; THEN would my code
> > > be better?
>
> > : SAMPLE DUP 0< IF 2 + ELSE 2 -THEN 2/ ;
>
> I see! So how would you do that?
>
> : SAMPLE DUP 0< IF 2 + 2/ ; THEN 2 - 2/ ;
>
> That works, but it duplicates all the code post-split. At least one
> extra call, unless there isn't any such code.

No it doesn't. At least not on the ANS Forths I use. When I type that
into bigForth
I get "unstructured ;". When I type it in to Win32Forth I get "Error:
; stack changed".

Now this will work:

: SAMPLE DUP 0< IF 2 + 2/ EXIT THEN 2 - 2/ ;

Regards,

John M. Drake

jeth...@gmail.com

unread,
Jul 13, 2006, 4:54:08 PM7/13/06
to
rickman wrote:
> j2th...@cavtel.net wrote:
> > Jeff Fox wrote:

> > > : SAMPLE DUP 0< IF 2 + ELSE 2 -THEN 2/ ;

> > I see! So how would you do that?

> > : SAMPLE DUP 0< IF 2 + 2/ ; THEN 2 - 2/ ;

or

> > : SAMPLE1 IF 2 + ; THEN 2 - ;
> > : SAMPLE DUP 0< SAMPLE1 2/ ;

> Have I missed something else? I guess it's obvious this is new to me.

> I don't know about obvious, but it is funny.

> I think you just did exactly what Jeff is talking about. You factored


> the example into two words using the semicolon style. Wasn't the point
> that it forces factoring? In fact, couldn't you do this a bit
> differently to

> : SAMPLE1 IF + ; THEN - ;
> : SAMPLE 2 OVER 0< SAMPLE1 2/ ;

Yes, that works this time. I was interested in the general case:

: GENERAL A IF B ELSE C THEN D ;

In this particular case you don't need a second branch.

: SAMPLE 2 OVER 0< IF NEGATE THEN - 2/ ;

If for some reason branches are expensive you can get rid of the other
branch too.

: SAMPLE 2/ DUP 0< 2* 1+ - ;

This works fine but it isn't particularly readable.

: SAMPLE ( +n|-n -- n' )
2/ dup 0< \ n/2 -1|0
2* 1+ \ n/2 -1|1
- \ +n/2-1 | -n/2+1
;


Back to the general case,

: GENERAL A IF B ELSE C THEN D ;

Ignoring the call to GENERAL and the call to A, we have either

a failed branch, a call to B and exit from B, a branch, a call to D and
tail-exit from D, or else
a branch, a call to C and exit from C, a call to D and tail-exit from
D.

My interpretation of Jeff's way (which might not be right) is

: SPECIFIC IF B ; THEN C ;
: GENERAL A SPECIFIC D ;

This gives us in one case a call to SPECIFIC , a failed branch, a call
to B and tail-exit from B, and a call to D and tail-exit from D.
In the other case we get a call to SPECIFIC, a branch, a call to C and
tail-exit from C, and a call to D and tail-exit from D.

So for efficiency the difference is my way we get either

an extra branch but one less call, and one return that isn't a
tail-return. or
one less call and one return that isn't a tail-return

It looks to me like when you stick that D on there, the difference in
efficiency is less.

But as you point out, Jeff's coding style does sometimes have the
advantage of requiring either duplication of code or extra factoring. I
didn't see that from Jeff's first example but I do from the second
example.

Some people might not see this as an advantage. I remember discussing
Forth with somebody on (I think) comp.object. He said that Forth was a
toy language that didn't provide the tools that were necessary for real
applications. I told him that Forth had the big advantage that when you
tried to write a single routine that was too complicated, it broke and
couldn't be fixed. It required you to organise things into pieces that
were simple enough to understand easily, and once you did that it
turned easy. He laughed at me. He said we'd gone into an
alice-in-wonderland world where up is down and weakness is strength. I
doubt he actually thought about it.

> My problem is that I run out of names for these sort of words.

Sometimes that can be a problem. But if they're factored well, they're
likely to do something specific.

: EXAMPLE1 ( n flag -- -n|n ) IF NEGATE THEN ;

A word that sometimes negates a word. MAYBE-NEGATE . ?NEGATE might do,
sometimes people put a ? on the front of a word that tests at the
beginning and conditionally does something, like ?DUP or ?DO . You
usually want a name that says what it does instead of how it does it.

: EXAMPLE1 ( n -- n' ) DUP 0< IF 2 + ELSE 2 - THEN ;

BUMP-BY-2 ? 2MORE-OR-LESS ? I'm not sure.

Usually long names are no problem. If long names are an issue you can
have the compiler use just the first three letters and a count, and
then you can deal with name clashes. Or you can run the source code
through a search-and-replace. Have it convert the first name to A0, the
second name to A2, and after A9 then go to B0, B1, B2, etc. Then your
names will all be 3 characters long and for all practical purposes your
code is encrypted. "I can write Dartmouth-Basic in any language!" Or if
your application doesn't need to interpret code, just throw alway the
names completely.

So use names that tell you what's going on if you can, and if you can't
then look for a better way to factor, and if neither one works you can
use names like EXAMPLE1 and think about some other problem until you're
ready to come back to this one.

John Passaniti

unread,
Jul 13, 2006, 5:54:46 PM7/13/06
to
jmdra...@yahoo.com wrote:
>> Your claim is that someone on this group has posted, saying that "the
>> inventor of Forth isn't doing Forth, doesn't understand Forth, know
>> what Forth word is ..."
>>
>> I don't believe it.
>
> Please see:
>
> http://groups.google.com/group/comp.lang.forth/browse_frm/thread/8cd76f7bc05d86c1/b7a9b2b336a2f20f?q=%22it's+not+forth%22&rnum=1#b7a9b2b336a2f20f
>
> There are other examples.

This is an example of what? When I go to the URL you provide, I see a
thread that changed title (when Jeff Fox changed it) in response to a
message from Rick Hohensee. Rick references a comment from a Marty
Fraeman on MISC designs; that the address register "is not Forth."

I don't know the original context of Marty's statement, and don't think
it really matters. My guess is "is not Forth" is a statement that the
MISC design doesn't map to *traditional* Forth systems. But since
Charles Moore is blazing new ground in Forth, I don't see the relevance.

This to me is kind of like saying that Philip Glass isn't composing
classical music because his music wasn't like Beethoven's.

Jeff Fox

unread,
Jul 13, 2006, 9:43:59 PM7/13/06
to
Paul E. Bennett wrote:
> While Jeff is right in that it only requires the programmer to keep count of
> the items he has on a stack, there are some error scenarios (mostly errant
> hardware) that would benefit from advanced warning of stack overflow and
> underflows. Why the hardware might be errant may be more to do with cosmic
> influences than any fault of design but the High Integrity Systems
> Development Community appreciate these little touches when they can be made
> available.
>
> Of course, when you have these errors get flagged up you need to deal with
> the situation.

The issue of high integrity systems and fault tolerance to cosmic
influences
is not related to using MISC opcodes, but it isn't unrelated to
SEAforth in that
the solution that I would propose would be parallelism and redundance
and
voting of parallel tracks. We will help let you do that on a chip or a
scalable
array of chips if you want to do that.

But the issue of cosmic rays on the instruction set seems a little like
the issue a hacker somehow having gotten inside of the hardware
so that when you load a value from internal memory a hacker on the
outside will corrupt the instruction load and so it will always require
sandboxes and security layers to recover from the activity of this
imagined hacker. It is not exactly where I would begin if I was trying
to explain how a simple instruction set works.

Andrew Haley

unread,
Jul 14, 2006, 5:58:36 AM7/14/06
to
jmdra...@yahoo.com wrote:

> Please see:

> http://groups.google.com/group/comp.lang.forth/browse_frm/thread/8cd76f7bc05d86c1/b7a9b2b336a2f20f?q=%22it's+not+forth%22&rnum=1#b7a9b2b336a2f20f

William Tanksley's posting, right?

Where? Where in that posting is it said (or even implied) that "the


inventor of Forth isn't doing Forth, doesn't understand Forth, know

what Forth word is ..." ?

> There are other examples.

Andrew.

jeth...@gmail.com

unread,
Jul 14, 2006, 7:37:00 AM7/14/06
to

> William Tanksley's posting, right?

> Where? Where in that posting is it said (or even implied) that "the
> inventor of Forth isn't doing Forth, doesn't understand Forth, know
> what Forth word is ..." ?

----------
>universal acceptance today that Forth means ANS and I often
>read that Chuck doesn't do Forth any more.

Don't be too offended -- this is what he himself said about OKAD.
Remember? No source means no Forth.
----------

William Tanksley quoted Jeff Fox saying that.

Jeff Fox

unread,
Jul 14, 2006, 11:49:49 AM7/14/06
to
Andrew Haley wrote:

I would like to than William for not reposting the most offensive of
posts.

I wish people would not call for reposting of offensive posts, it
is an offensive tactic. Why do people want to turn these threads
into that?

If I wanted to see nastiness and name calling again I would
have responeded with posting it again as you called for that
instead of discussions of programming.

Is is just time for another thread to be declared taken over
by people who refuse to allow a discussion of the subject
listed as the subject in the subject line?

Jeff Fox

unread,
Jul 14, 2006, 12:08:01 PM7/14/06
to
j2th...@cavtel.net wrote:

I really wish people on the ANS committee would have made even
the slightest effort to understand what Mr. Moore was talking about
when he petitioned for them to consider several simple ideas for
their standard as they had been common practice for years. I
think the way they acted was nearly criminal.

But to still be pretending to be this dumb twenty years later is
shameful. Ok, you haven't wanted to understand the explanations
and you don't want other people to understand either so you come
up with the most bizzare argumements to confuse people and
continue to make noise. Twenty years of noise is not yet enough
for you.

If you insist on your posting the majority of information in this
thread,
and intentionally getting this wrong, advocating
complete rejection of the concept of small, fast 5-bit Forth tokens,
that are native code,
that don't have the overhead of calls and returns,
that aren't the 'byte code' tokens that you have taked about for years,
that demonstrate something more modern than ANS syntax,
and keep insisting that efficiency is bad and more overhead is good,
and that the most important thing is using the same sytax from
30 years ago,
and that you can make noise and argue forever and make noise
forever that tradition is more important than progress we can
stick with those 30 year old interpreted bycode concepts and
reuse to even disucss how to make things smaller, cheaper, and
faster, or simpler and eaiser.

All of your arguemnts end up with your claiming that a 2000%
decrease in efficiency is always a good thing to you. ok.

Let's say you own the thread from now on and
can continue to try to confuse others in this one.

I think there could be no better recommendation
that there is something there to be considered
when people who have refused to consider it for
twenty years still feel so compelled to jump in and
make the most noise about other things when
other people do want to disucss these topics.

Are you just afraid that people will see how dumb
fighting against all of this because understanding
might effect the habit of using ELSE or understand
what Mr. Moore was talking about twenty years ago
when you rejected these ideas out of hand for
inclusion in what many people in c.l.f have told us
"IS" Forth now that Forth means ANS Forth.

If I comment again in this thread I will relabel it
ANS Forth committee member still won't allow
discussions of MISC after twenty years, or
more calls for hate speech to be quoted again.

Andrew Haley

unread,
Jul 14, 2006, 2:18:41 PM7/14/06
to
Jeff Fox <f...@ultratechnology.com> wrote:
> Andrew Haley wrote:

> I would like to than William for not reposting the most offensive of
> posts.

> I wish people would not call for reposting of offensive posts, it
> is an offensive tactic. Why do people want to turn these threads
> into that?

Lest anyone forget how this digression started, you posted this
comment in this thread:

> Jeff Fox <f...@ultratechnology.com> wrote:
>> so many people in c.l.f say that they know so much about Forth that
>> they know that the inventor of Forth isn't doing Forth, doesn't
>> understand Forth, doesn't know what Forth word is, doesn't know what
>> a stack is, and simply doesn't understand programming or computers.

> If I wanted to see nastiness and name calling again I would have


> responeded with posting it again as you called for that instead of
> discussions of programming.

> Is is just time for another thread to be declared taken over by
> people who refuse to allow a discussion of the subject listed as the
> subject in the subject line?

I have a suggestion. I'll stop posting on this subject, and you'll
stop accusing unnamed posters to c.l.f. of slandering Chuck Moore.

Andrew.

Brad Eckert

unread,
Jul 14, 2006, 2:20:32 PM7/14/06
to

Jeff Fox wrote:
>
> I really wish people on the ANS committee would have made even
> the slightest effort to understand what Mr. Moore was talking about
> when he petitioned for them to consider several simple ideas for
> their standard as they had been common practice for years. I
> think the way they acted was nearly criminal.
>

Are you talking about multiple entry points? I like those too.
Unfortunately, many Forths put headers and code in the same place so it
would been a lot to ask. OTOH, I think one could fake it. For example,
;; could lay down a jump and : could be modified to resolve the jump.

Okay, several good ideas that were common practice went into decline
with the introduction of ANS. What were they?

--Brad

Ed

unread,
Jul 14, 2006, 9:22:19 PM7/14/06
to

"Jeff Fox" <f...@ultratechnology.com> wrote in message news:1152893281....@75g2000cwc.googlegroups.com...

> j2th...@cavtel.net wrote:
>
> I really wish people on the ANS committee would have made even
> the slightest effort to understand what Mr. Moore was talking about
> when he petitioned for them to consider several simple ideas for
> their standard as they had been common practice for years. I
> think the way they acted was nearly criminal.

Nearly everyone will have views about what's "good" for Forth
- in particular, what ANS Forth "should have" included.

As a Forther once put it to me, ANS Forth was primarily about
making Forth acceptable to the *rest* of the computing industry.
Hobbyists and enthusiasts don't need standards but standards are
essential for commercial viability.

With that in mind, it was appropriate ANS Forth should leave
out non-essentials or things that amount to personal wishlists.
Whether this continues remains to be seen.

As regards Mr. Moore, I suspect he and mainstream Forth went
their separate ways long ago :)

John Doty

unread,
Jul 14, 2006, 11:04:16 PM7/14/06
to
Ed wrote:

> With that in mind, it was appropriate ANS Forth should leave
> out non-essentials or things that amount to personal wishlists.

If ANS Forth had actually done this, there would be little to criticize.
But many non-essentials are present. ANS Forth is a compendium of the
pet kludges of traditional Forthers.

--
---
John Doty, Noqsi Aerospace, Ltd.
---
His diagnosis of the hostility ... reflects the willful blindness of the
invader who assures himself that the natives are only made unfriendly by
some other provocation than his own. -Barbara W. Tuchman

jeth...@gmail.com

unread,
Jul 15, 2006, 1:56:00 AM7/15/06
to

Jeff Fox wrote:

> All of your arguemnts end up with your claiming that a 2000%
> decrease in efficiency is always a good thing to you. ok.

"Never attribute to malice what can be more easily explained by
stupidity."

Jeff, you have a lot of experience at something I have very little
experience with. I've been trying to follow your reasoning. When I get
it wrong, that's an opportunity for you to say what you actually mean.
Maybe somebody else will understand it when it gets laid out carefully.

You seem to think I'm opposing you when I pay attention to you. I tell
you what I don't understand and you think I'm saying you're wrong.

Apart from your rancor I think I have learned some things from you. It
sounds like Chuck really has found a way to radically simplify Forth.

You pointed out the branching system that eliminates ELSE and also
makes it *easier* to optimise tail-recursion. Entirely apart from the
question whether it's easier to program in after you get used to it, or
easier to test, or easier to write simple code in, it *is* a simpler
Forth with less baggage in the internals.

Maybe you can tell me if I have the wrong idea about colors. I get the
impression that when you write in ColorForth you get to choose what
color each word will be. One color means it gets compiled into a
definition, another color means it gets executed immediately. And if
you wanted to print out that Forth in a more-or-less-readable way
without a color printer, one way would be to print extra words to
represent the colors. For words that get executed you could have a [ in
front, for words that get compiled you could have a ] and so on. (And
to make it even more readable, instead of repeating the color words
each time you might put in a new one only when it was different from
the last one, or even leave it out after : etc.)

I thought of this simplification but I couldn't bring myself to do it
because of the extra keystrokes. If we didn't have any immediate words,
but just did [ IF and [ DO and [ ' and such, we could get rid of
state-smart words, get rid of immediate words, get rid of STATE , the
whole entire complicated mess. Just gone. But it takes extra keystrokes
and the extra [ would clutter up the code. It looks to me like Chuck
did that. You don't see the extra [ because it's keystrokes that change
the color, they aren't visible keystrokes. A Forth that's radically
simpler. Just by throwing out the defaults. You don't have to remember
which words are Forth words and which are Compiler words, or just how
to make each of them do the nondefault behavior. Just tell the system
whether you want to execute now or later, and that's what happens.

I like it.

Marcel Hendrix

unread,
Jul 15, 2006, 6:06:21 AM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> Re: using MISC (post 1987 Forth hardware) opcodes
[..]

> If we didn't have any immediate words,
> but just did [ IF and [ DO and [ ' and such, we could get rid of
> state-smart words, get rid of immediate words, get rid of STATE , the
> whole entire complicated mess. Just gone.

But [ would have to be an IMMEDIATE word.

And of course, you would need to *know* that IF is a compiler or an
executioner in order to correctly specify the [ or not.

Prepending a [ or ] would make it necessary to have two versions
of all words. Making FIND smarter is a solution to that, but then
the simplicity of the Forth compiler is going down the drain :-)

[..]

> I like it.

-marcel


Mark W. Humphries

unread,
Jul 15, 2006, 4:55:07 AM7/15/06
to
Marcel Hendrix wrote:
[snip]

> Prepending a [ or ] would make it necessary to have two versions
> of all words. Making FIND smarter is a solution to that, but then
> the simplicity of the Forth compiler is going down the drain :-)

How so?

FIND doesn't have to be very smart, it just needs to know if you're
looking for the interpretation xt or compilation xt of a word, which
are the same for the great majority of words.

lookup ( a # mask -- {lfa -1} |0 ) \ looks up a word in the
dictionary

when compiling: .... tibcount compilation lookup ....
when interpreting: .... tibcount interpretation lookup ....

Cheers,
Mark

Marcel Hendrix

unread,
Jul 15, 2006, 7:20:50 AM7/15/06
to
"Mark W. Humphries" <m...@intranetsys.com> writes Re: using MISC (post 1987 Forth hardware) opcodes

> Marcel Hendrix wrote:
> [snip]
>> Prepending a [ or ] would make it necessary to have two versions
>> of all words. Making FIND smarter is a solution to that, but then
>> the simplicity of the Forth compiler is going down the drain :-)

> How so?

The idea of the OP was to simplify the Forth system with this idea.

Having two words with the same name and possibly different behavior
also creates complications with CREATE (unless the user is required
to explicitly define the two words), ' (which xt is meant), FORGET
(you can just leave it out, how's that for simplification), WORDS
(how to show/what to show), VOCABULARY , MARKER ...

> FIND doesn't have to be very smart, it just needs to know if you're
> looking for the interpretation xt or compilation xt of a word, which
> are the same for the great majority of words.

I have no problems with a "complicated" compiler/FIND, the OP has?

Most technical inventions/software only look simple because people
don't (need to) understand how they work.

-marcel

Mark W. Humphries

unread,
Jul 15, 2006, 6:14:11 AM7/15/06
to
Marcel Hendrix wrote:
[snip]

> Having two words with the same name and possibly different behavior
> also creates complications with CREATE (unless the user is required
> to explicitly define the two words),

Define two words, BUT this applies only to the rare cases where we
need/want different xts for compilation and interpretation. For example
to use the name " instead of having ["] and "
Having two different definitions, one for compile-time, one for
interpret-time, is just a bonus that comes with a more discriminating
FIND that gives us an easy way to avoid state-smart words and
aberrations like ["] or .( should we want to.

For example, definitions of "

: " ( -- a # ) here char " parse tuck here swap cmove ;
: " ( -- ) compile " ," align ; directive

>' (which xt is meant),

The interpretation xt, use C' to get the compilation xt (in most cases
both return the same xt).
Same applies to [']

>FORGET (you can just leave it out, how's that for simplification)

I agree :)

>WORDS (how to show/what to show)

One option is to have WORDS take a mask as a parameter: ...
interpretation words ... compilation words ...
Another option is to treat it as a user interface issue and highlight
them in some particular way, same thing applies now to immediate words
I guess.

>VOCABULARY, MARKER ...
I don't see any issue with either.

[snip]

Cheers,
Mark

Howerd Oakford

unread,
Jul 15, 2006, 6:30:41 AM7/15/06
to
Hi rickman,

Nice post ;)

[snip]

> I don't think I am giving up my ELSE just yet.
When I first came across the ELSEless IF it threw me too.
It makes more sense in the colorForth context, where you can drop right
out of a word and into the next. If you can't do that, ELSE becomes
more useful.

Its a bit like a maze with different people in different places - some
people know that Left-Left-Right will get them to the centre, others
know its Right-Left-Right.
It depends where you start from...

Regards

Howerd 8^)

Stephen J. Bevan

unread,
Jul 15, 2006, 10:42:36 AM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> writes:
> I thought of this simplification but I couldn't bring myself to do it
> because of the extra keystrokes. If we didn't have any immediate words,
> but just did [ IF and [ DO and [ ' and such, we could get rid of
> state-smart words, get rid of immediate words, get rid of STATE , the
> whole entire complicated mess. Just gone. But it takes extra keystrokes
> and the extra [ would clutter up the code.

Instead of using "[" "]" to surround "IF" I do the opposite which is
to use "{" "}" to delimit words that should be compiled. Yes it adds
some clutter but usually no more than 4-8 chars per definition given
that I try to keep words to one line and with at most one conditional
(there is no DO, BEGIN, ... etc., (tail)-recursion is used instead)
Here's an example :-

$ cat cat.opf
#< std.opf
#< posix.opf
: cell+ { 4 + } ;
: 2drop { drop drop } ;
: script-name { argv @ dup "# } ;
: buffer# 800 #, ;
buffer# allot : buffer #, ;
: read { push buffer# buffer pop posix-read } ;
: write { buffer 1 posix-write drop } ;
: close { posix-close drop } ;
: cat-fd { dup read } if { write cat-fd } ; then { 2drop } ;
: open { push 0 posix-o-rdonly pop posix-open } ;
: error { script-name type space } ." could not open " { dup "# type cr } ;
: cat-file { dup open } if { nip dup cat-fd close } ; then { drop error } ;
: do-all if { 1 - swap dup @ cat-file cell+ swap do-all } ; then { 2drop } ;
: skip-name { argv cell+ argc 1 - } ;
: main { skip-name do-all } ;
main

and the (minimal) documentation :-

$ cat cat.txt
A simple version of cat(1).

This version only works on files, it does not accept standard input.

read ( fd[n] -- n )
Reads <code>buffer#</code> bytes into <code>buffer</code> returning
the number read.

write ( nbytes[n] -- n )
Writes <code>nbytes</code> from <code>buffer</code> to the standard output
returning the number of bytes written.

close ( fd[n] -- )
Close the file descriptor and ignore the result.

cat-fd ( fd[n] -- )
Reads from fd in <code>buffer#</code> chunks and writes the chunks to
the standard output.

open ( file-name[c-addr] -- fd[n] )
Opens the NUL terminated <code>file-name</code> and returns the
file descriptor <code>fd</code>. If <code>fd</code> is less than
or equal to 0 then the file could not be opened.

error ( file-name[c-addr] -- )
Output an error message containing the script and file-name.

cat-file ( file-name[c-addr] -- )
Writes the contents of <code>file-name</code> to the standard output
or reports an error if it cannot be opened.

do-all ( a-addr u -- )
Applies <code>cat-file</code> to all the command line arguments.


The { } in the code probably look like unnecessary clutter to people
used to writing in ANS Forth but the benefit of that "clutter" is
simplification in other areas as you alluded to.

jeth...@gmail.com

unread,
Jul 15, 2006, 11:09:20 AM7/15/06
to
Marcel Hendrix wrote:
> "j2th...@cavtel.net" <jeth...@gmail.com> Re: using MISC (post 1987 Forth hardware) opcodes

> > If we didn't have any immediate words,


> > but just did [ IF and [ DO and [ ' and such, we could get rid of
> > state-smart words, get rid of immediate words, get rid of STATE , the
> > whole entire complicated mess. Just gone.

> But [ would have to be an IMMEDIATE word.

Yes, the only one. It could be built into the compiler or something.

> And of course, you would need to *know* that IF is a compiler or an
> executioner in order to correctly specify the [ or not.

If you compile everything and then execute later, all you'd need to
know is that you want it to do something now and not later. It would
have one behavior. If you want to make a branch now, do [ IF . If you
want to compile the word that will make a branch later, do IF .

> Prepending a [ or ] would make it necessary to have two versions
> of all words. Making FIND smarter is a solution to that, but then
> the simplicity of the Forth compiler is going down the drain :-)

No, each word would have one behavior. One behavior, one word. [ just
tells you to do it now while you're compiling. It's simpler
conceptually, but it removes some semantic sugar that we're all used
to.

So for example, ' would parse the next word, look it up, and leave its
xt (the word's only xt) on the stack. To do ['] you'd do

.... [ ' FOO LITERAL ] ....

or if you preferred to have [ work only on the next word, it would look
like

.... [ ' FOO [ LITERAL ....

You could do everything you can do in a regular Forth in a Forth that
always compiles. It wouldn't be nearly as complicated as a regular
Forth, you could throw away the list of immediate or compile-only
words, you would get rid of the words that secretly have two different
behaviors that superficially look the same, you'd get rid of IMMEDIATE
. If [ acts only on the next word you'd get rid of STATE .

<b>But</b> you'd be losing some semantic sugar that people have enjoyed
for 40 years or so. Sometimes you'd use 4 words where we've enjoyed
using one. The language you use would be closer to the way the system
actually works, but it would be less convenient.

And so it would be only natural to invent words like ']

: '] ' LITERAL ;

and then do

.... [ '] FOO ....

and we might wind up with almost the same thing we have now.

Meanwhile the various people who're writing compile-only Forths act
like they don't miss being able to interpret code in midline. By giving
up that capability they make it even simpler.

I'm used to interpreting while compiling, and I don't want to give it
up, but maybe that's the best way to go. Give up lots of complexity.
Maybe you could keep the behaviors that don't compile into a definition
easily too, maybe one command that says 'continue the existing
definition', and then whenever you want to just do stuff you start a
new line and don't put that command in front.. To go back to compiling
a definition you skip to a new line and add that command.

: MY-WORD COMPILING RIGHT ALONG ....
STACK-SIZE @ BUFFER-SIZE @ + LITERAL
] CONTINUING MORE COMPILING ....

jeth...@gmail.com

unread,
Jul 15, 2006, 11:23:18 AM7/15/06
to

Stephen J. Bevan wrote:

> Instead of using "[" "]" to surround "IF" I do the opposite which is
> to use "{" "}" to delimit words that should be compiled. Yes it adds
> some clutter but usually no more than 4-8 chars per definition given
> that I try to keep words to one line and with at most one conditional
> (there is no DO, BEGIN, ... etc., (tail)-recursion is used instead)

Thank you.

> : buffer# 800 #, ;
> buffer# allot : buffer #, ;

This stood out to me. I always assumed that

17 CONSTANT my-constant

was more efficient than

: my-constant 17 ;

because otherwise CONSTANT could be left out. Is that really true for
everybody?

Or is the conceptual value of having some words labeled CONSTANT worth
the small complication?

Marcel Hendrix

unread,
Jul 15, 2006, 1:47:05 PM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> writes Re: using MISC (post 1987 Forth hardware) opcodes

> Marcel Hendrix wrote:
[..]


>> And of course, you would need to *know* that IF is a compiler or an
>> executioner in order to correctly specify the [ or not.

> If you compile everything and then execute later, all you'd need to
> know is that you want it to do something now and not later.

OK, I had missed that assumption.

So if you have a deferred word FOO and you want it to do DUP :

[ : mydup ] DUP
[ ' mydup [ LITERAL IS FOO

and not

[ ' DUP [ LITERAL IS FOO

Or is it?

-marcel

Marc Olschok

unread,
Jul 15, 2006, 12:36:57 PM7/15/06
to
Adam Warner <use...@consulting.net.nz> wrote:
> On Wed, 12 Jul 2006 09:50:45 -0700, Jeff Fox wrote:
>
> > You have to understand the conceptual foundation about how Forth code
> > should be constructed and factored. And people do get confused about how
> > code can have short words and lots of : and ; and also use a minimal
> > amount of the stacks!
>
> Again, you can only use a bounded amount of stack with tail recursion or
> the translation of a recursive definition into an iterative form.
>
> A tail recursive Forth word will call RECURSE as the last thing it does
> before exiting the word. A Forth compiler can translate this call into a
> jump to the start of the word.
>
> A tail recursive definition is typically harder to write than a non-tail
> recursive definition.

At least for primitive recursive functions a doubt that.

> Here's an example I came up with within the
> limitations of my Forth knowledge: Write recursive and tail recursive
> words to naively sum the integers from 1 to the first element on the stack.

Perhaps this is just not a good enough example to support your claim.
Or it may depend on the particular Forth dialect used.
In Retroforth I found

: trsum ( s n -- s' ) 0; tuck + swap 1- trsum ;

quite intuitive.
Instead of "recurse" it uses the definitions name, which I find more
readable anyway.
The other nice feature is 0; :
it leaves the current definition if the
if the TOS is 0 it consumes the TOS and leaves the current word,
if the TOS is nonzero then nothing is done (in particular the TOS
is not consumed). Hence you do not need IF...THEN constructs and
the cleanup afterward.

>[...]
> If your Forth does not have decent sized stacks then you cannot
> effectively run recursive definitions, you cannot prototype using
> recursive definitions and you will be inhibited from even thinking
> recursively. You'll be forced into premature optimisation, writing harder
> code for a less expressive Forth.

I have never experienced such a problem.

Marc

Marcel Hendrix

unread,
Jul 15, 2006, 2:48:33 PM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> writes Re: using MISC (post 1987 Forth hardware) opcodes
[..]
> I always assumed that

> 17 CONSTANT my-constant

> was more efficient than

> : my-constant 17 ;

> because otherwise CONSTANT could be left out. Is that really true for
> everybody?

I can't answer for everybody, but for iForth and, I guess, Quartus,
VFX, SwiftForth, bigForth, SPF etc. it is.

FORTH> : my-constant 17 ; ok
FORTH> : tt my-constant 3 + drop ; ok
FORTH> ' tt idis
$00529F00 : [trashed]
$00529F08 ;
FORTH> my-constant 3 + . 20 ok
FORTH> : uu my-constant 3 + dup swap over rot drop 2drop ; ok
FORTH> ' uu idis
$00529F80 : [trashed]
$00529F88 ;

-marcel

jeth...@gmail.com

unread,
Jul 15, 2006, 5:25:09 PM7/15/06
to

Marcel Hendrix wrote:
> "j2th...@cavtel.net" <jeth...@gmail.com> writes Re: using MISC (post 1987 Forth hardware) opcodes

> > If you compile everything and then execute later, all you'd need to


> > know is that you want it to do something now and not later.

> OK, I had missed that assumption.

> So if you have a deferred word FOO and you want it to do DUP :

> [ : mydup ] DUP
> [ ' mydup [ LITERAL IS FOO

> and not

> [ ' DUP [ LITERAL IS FOO

> Or is it?

I'm using my imagination in line with what John Doty said. Suppose that
the compiler compiles a line of source code at a time. And at the end
of each line it either has the start (and maybe the end) of a new
command, or else it executes the line and throws it away.

Then you could do

.... '
DUP
IS
FOO

and it ought to work.
First it compiles the line that ends with ' . If it isn't compiling a
definition then it executes the line. ' executes and looks at the
beginning of the next line to find DUP and leave its xt on the stack.

You could have the compiler pick up and compile the rest of that line,
but just in case it's simpler I ended that line here. Next you compile
IS and at the end of the line, execute it. IS parses the next line for
a deferred command and finds it, FOO . It puts the top stack item into
FOO .

Separating parsing words from the text they parse isn't any big
difficulty, and it lets you first compile them and then execute them.

To execute things inside a definition you'd need either a command to
say execute the next line instead of adding it to the current
definition, or a command to say add the next line to the current
definition instead of executing it. I'd tend toward making execution
the default and the nondefault command says to add it to the current
command. Either way could be made to work.

So the code that executes during compilation gets a new line and it
stands out to the eye as well as to the compiler.

I don't know whether this fits with curent practice in non-interpreted
Forth, but it looks like it could be done.

>> And of course, you would need to *know* that IF is a compiler or an
>> executioner in order to correctly specify the [ or not.

Yes, if you interpret-or-compile then you have to know. But suppose you
complicate the system trying to make words that pretend to do the same
thing regardless, but sometimes they do it all *now* while other times
they do some of it now and compile code to do some of it later. Your
Forth system has added complexity whose purpose is to hide from you
what it's doing. I have to admit that can be convenient. I just think
there ought to be a better way.

I like the idea of just deciding on the spot which things to do now and
which to do later. ColorForth lets you decide on the spot by assigning
a color. Compile-always Forths could perhaps decide with a newline.
Each line executes after compilation and throws away the compiled code,
or it compiles and keeps the code. The first executed item can tell it
to stop executing and keep the code.

Compile-only systems can give you all the compiled control structures
outside of definitions, with no extra complexity required. No [IF]
[ELSE] [THEN], nothing special about interpreted loops. But there may
be a limitation about how much code you can put on a single line.

Marcel Hendrix

unread,
Jul 15, 2006, 8:03:26 PM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> writes Re: using MISC (post 1987 Forth hardware) opcodes

> Marcel Hendrix wrote:
[..]


>> So if you have a deferred word FOO and you want it to do DUP :

>> [ : mydup ] DUP
>> [ ' mydup [ LITERAL IS FOO

>> and not

>> [ ' DUP [ LITERAL IS FOO

>> Or is it?

> I'm using my imagination in line with what John Doty said. Suppose that
> the compiler compiles a line of source code at a time. And at the end
> of each line it either has the start (and maybe the end) of a new
> command, or else it executes the line and throws it away.

> Then you could do

> .... '
> DUP
> IS
> FOO

> and it ought to work.

Very tricky, nice :-)

The problem could be that you have forced this Forth to give you the
xt of an executable DUP, which it may not have (when it is an
optimizing Forth), because it assumed it always could compile one
on-the-fly and throw it away afterwards. (It may be general problem
with ' and ['] in such a system.)

[..]

> Each line executes after compilation and throws away the compiled code,
> or it compiles and keeps the code. The first executed item can tell it
> to stop executing and keep the code.

I guess a simple system will only be able to keep a named definiton,
not an arbitrary header- and epilogue-less piece of code.

> Compile-only systems can give you all the compiled control structures
> outside of definitions, with no extra complexity required. No [IF]
> [ELSE] [THEN], nothing special about interpreted loops. But there may
> be a limitation about how much code you can put on a single line.

Simple, uncomplicated, transparent, indeed :-(

-marcel

Stephen J. Bevan

unread,
Jul 15, 2006, 11:15:49 PM7/15/06
to
"j2th...@cavtel.net" <jeth...@gmail.com> writes:

> Stephen J. Bevan wrote:
>> : buffer# 800 #, ;
>> buffer# allot : buffer #, ;
>
> This stood out to me. I always assumed that
>
> 17 CONSTANT my-constant
>
> was more efficient than
>
> : my-constant 17 ;
>
> because otherwise CONSTANT could be left out. Is that really true for
> everybody?
>
> Or is the conceptual value of having some words labeled CONSTANT worth
> the small complication?

At least in my implemenation "x CONSTANT y" would result in the same
code being generated as ": y x #, ;". Thus the question of which to
use is a matter of taste. I don't have a taste for CONSTANT, or
most words that parse the input, ":" already does a good job of that,
so I prefer to use ":" in combination with other words to achieve the
desired effect.

Adam Warner

unread,
Jul 16, 2006, 12:56:27 AM7/16/06
to
On Sat, 15 Jul 2006 16:36:57 +0000, Marc Olschok wrote:

>> Here's an example I came up with within the
>> limitations of my Forth knowledge: Write recursive and tail recursive
>> words to naively sum the integers from 1 to the first element on the stack.
>
> Perhaps this is just not a good enough example to support your claim.
> Or it may depend on the particular Forth dialect used.
> In Retroforth I found
>
> : trsum ( s n -- s' ) 0; tuck + swap 1- trsum ;
>
> quite intuitive.
> Instead of "recurse" it uses the definitions name, which I find more
> readable anyway.
> The other nice feature is 0; :
> it leaves the current definition if the
> if the TOS is 0 it consumes the TOS and leaves the current word,
> if the TOS is nonzero then nothing is done (in particular the TOS
> is not consumed). Hence you do not need IF...THEN constructs and
> the cleanup afterward.

Thanks for the nice example!

>>[...]
>> If your Forth does not have decent sized stacks then you cannot
>> effectively run recursive definitions, you cannot prototype using
>> recursive definitions and you will be inhibited from even thinking
>> recursively. You'll be forced into premature optimisation, writing harder
>> code for a less expressive Forth.
>
> I have never experienced such a problem.

We agree I did not provide a good enough example to support my claim. This
one should be bulletproof: You have a reason to trace though a deep
tree-like data structure. Mechanically this involves pushing paths you
still need to travel onto a stack every time you branch within the tree.
Recursion makes this mechanical process invisible.

Here's part of the data structure. I'll describe tracing through the right
size of the solid region:

a
/ \
b c
. / \
. d e
. . . / \
. . f g
. . / \
. h i
. / \
. j k
. / \
. l m
. / \
. n o
. / \
. p q
. .
. .
. . .
. . .

1. Push (b) and process (c).
2. Push (d) and process (e).
3. Push (f) and process (g).
4. Push (h) and process (i).
5. Push (j) and process (k).
6. Push (l) and process (m).
7. Push (n) and process (o).
8. Push (p) and process (q). Return.
9. Pop (p) and process. Return.
10. Pop (n) and process. Return.
11. Pop (l) and process. Return.
12. Pop (j) and process. Return.
13. Pop (h) and process. Return.
14. Pop (f) and process. Return.
15. Pop (d) and process. Return.
16. Pop (b) and process. Return.

An environment with six cell stacks cannot traverse this data structure
(without implementing userspace stacks out of heap memory). The stack is
blown around point 7 (earlier if there is already data on the return stack).

A six cell environmental dependency is simply too low for general purpose
programming tasks. Whoever is willing to concede this (by highlighting a
specialised embedded environment) should beware of claiming that such a
restricted environment is also easier to program.

Regards,
Adam

William James

unread,
Jul 16, 2006, 3:14:23 AM7/16/06
to
j2th...@cavtel.net wrote:
> Jeff Fox wrote:
> > j2th...@cavtel.net wrote:
> > > Easier to write? If my Forth compiler was arranged so that I could do a global
> > > replace through my code and change every ELSE to ; THEN would my code
> > > be better?
>
> > : SAMPLE DUP 0< IF 2 + ELSE 2 -THEN 2/ ;

: diminish over 0< if negate then - ;
: sample 2 diminish 2/ ;

>
> I see! So how would you do that?
>
> : SAMPLE DUP 0< IF 2 + 2/ ; THEN 2 - 2/ ;
>
> That works, but it duplicates all the code post-split. At least one
> extra call, unless there isn't any such code.
>
> : SAMPLE1 IF 2 + ; THEN 2 - ;
> : SAMPLE DUP 0< SAMPLE1 2/ ;
>
> That gets rid of the duplication of code but it needs an extra call.
>
> Have I missed something else? I guess it's obvious this is new to me.

jmdra...@yahoo.com

unread,
Jul 16, 2006, 5:52:59 PM7/16/06
to

Adam Warner wrote:

> We agree I did not provide a good enough example to support my claim. This
> one should be bulletproof: You have a reason to trace though a deep
> tree-like data structure. Mechanically this involves pushing paths you
> still need to travel onto a stack every time you branch within the tree.
> Recursion makes this mechanical process invisible.

That's not a problem. All you have to do is to use a threaded tree.

See: http://datastructures.itgo.com/trees/tbt.htm

> An environment with six cell stacks cannot traverse this data structure
> (without implementing userspace stacks out of heap memory). The stack is
> blown around point 7 (earlier if there is already data on the return stack).

Or without altering the data structure and using a threaded tree.

> A six cell environmental dependency is simply too low for general purpose
> programming tasks. Whoever is willing to concede this (by highlighting a
> specialised embedded environment) should beware of claiming that such a
> restricted environment is also easier to program.
>
> Regards,
> Adam

I fail to see how such an enviornment is "restricted". As Jeff pointed
out
one can always implement "stacks in memory" if that's what someone
REALLY wants/needs to do. He did that on the F21 in order to support
an ANS Forth. But is that how you want your stacks to GENERALLY
be made? If I can have a MUCH faster hardware stack and then on
occassion use an in-memory stack (or be more thoughtfull on my
data structure choice) how am I at a disadvantage from using an
in-memory stack all of the time?

Regards,

John M. Drake

jmdra...@yahoo.com

unread,
Jul 16, 2006, 6:25:51 PM7/16/06
to

Marc Olschok wrote:
> Perhaps this is just not a good enough example to support your claim.
> Or it may depend on the particular Forth dialect used.
> In Retroforth I found
>
> : trsum ( s n -- s' ) 0; tuck + swap 1- trsum ;

Nice! Here's what I came up in ColorForth.

: sum 0 swap
: sloop dup push + pop -1 + if sloop ; then drop ;

Max stack depth needed is 3.

And, as Jeff pointed out, you do have control structures in ColorForth
so you can write:

: sum 0 swap for i + next ;

Regards,

John M. Drake

John Doty

unread,
Jul 17, 2006, 12:47:03 PM7/17/06
to
Adam Warner wrote:


> We agree I did not provide a good enough example to support my claim. This
> one should be bulletproof: You have a reason to trace though a deep
> tree-like data structure.

Ok, that might be an application requirement. Not a particularly common
one in my experience.

So put a stack in memory. It doesn't necessarily have to be heap if you
have a reasonable upper bound on the required stack size.

No application requirement forces you to use the number stack to store a
complicated data structure. Indeed, I expect most experienced Forthers
would not do it this way.

When I did something similar many years ago, I found it useful to keep
the tree traversal state on a separate stack even though I had a big
number stack in that particular Forth implementation. For this kind of
problem, a separate stack helps minimize stack gymnastics and
facilitates factoring. These advantages more than compensate for the
trivial extra complexity of explicitly creating and destroying frames on
an auxiliary stack.

A language likes C creates and destroys frames suitable for this kind of
thing willy-nilly whether you need them or not. Forth makes you ask.
That's not much of a burden as far as I'm concerned. It's rare to have
an application requirement push you in this direction in Forth.

So, it seems to me that your objection to small stacks comes down to
"They won't let me write the code the way I want". That's not an
application requirement, so you don't have a serious problem unless the
small stack makes it significantly more difficult to code readably to
the real application requirements. That's not the case here: the extra
difficulty is trivial, and I think in a real application the way you
want to do it would actually be more difficult to code and read.

--

John Doty, Noqsi Aerospace, Ltd.
--

Beheading a man with a stone axe is difficult, and the axe blade quickly
loses its sharp edge and is tedious to resharpen. -Jared Diamond

ward mcfarland

unread,
Jul 17, 2006, 3:13:05 PM7/17/06
to
John Doty <j...@whispertel.LoseTheH.net> wrote:

> For this kind of
> problem, a separate stack helps minimize stack gymnastics and
> facilitates factoring.

You forgot to mention how much a separate stack will facilitate
debugging for this sort of thing ;-)

ast...@netcourrier.com

unread,
Jul 17, 2006, 3:51:09 PM7/17/06
to
>
> Some people might not see this as an advantage. I remember discussing
> Forth with somebody on (I think) comp.object. He said that Forth was a
> toy language that didn't provide the tools that were necessary for real
> applications.

Oh yeah, Forth looks like a toy to a lot of people who would die in 30
seconds if they don't have a handful of DVDs for librairies and
programming environment.

> I told him that Forth had the big advantage that when you
> tried to write a single routine that was too complicated, it broke and
> couldn't be fixed. It required you to organise things into pieces that
> were simple enough to understand easily, and once you did that it
> turned easy. He laughed at me. He said we'd gone into an
> alice-in-wonderland world where up is down and weakness is strength. I
> doubt he actually thought about it.
>

Well, forget him. You just stated that Forth doesn't work very well if
you do not respect the rule that appears on page one of 'programming
for dummies'.

> > My problem is that I run out of names for these sort of words.
>
> Sometimes that can be a problem. But if they're factored well, they're
> likely to do something specific.
>
[...]
> Usually long names are no problem. If long names are an issue you can
> have the compiler use just the first three letters and a count, and
> then you can deal with name clashes. Or you can run the source code
> through a search-and-replace. Have it convert the first name to A0, the
> second name to A2, and after A9 then go to B0, B1, B2, etc. Then your
> names will all be 3 characters long and for all practical purposes your
> code is encrypted. "I can write Dartmouth-Basic in any language!" Or if
> your application doesn't need to interpret code, just throw alway the
> names completely.
>

I think that multiple entry/exit points gets around this in colorForth.
In my Forth, which is also ELSE-less, I have nameless definitions. for
instance:
:: A IF B ; THEN C ;
: GENERAL A IDEM D ;
... where IDEM is an immediate word that compiles the most recent
nameless definition.
But often writing code without ELSE leads to a different way to factor
things, and the GENERAL problem disappears in the process; in
particular, code duplications due to the missing ELSE are quite rare.
In other words, evaluating the impact of dropping ELSE on efficiency by
counting bytes and cycles in the general case is unfair, because it is
actually the nearly the worst case.

Globally, I think the penality of the missing ELSE is less than zero
because of the many times where the missing ELSE enforces thinking a
little more and finding a better way to factor things.

Give it a try!

Amicalement
Astrobe

Ed

unread,
Jul 17, 2006, 11:38:14 PM7/17/06
to

"John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:_sGdnQ6NMZeDxiXZ...@wispertel.com...

> Ed wrote:
>
> > With that in mind, it was appropriate ANS Forth should leave
> > out non-essentials or things that amount to personal wishlists.
>
> If ANS Forth had actually done this, there would be little to criticize.
> But many non-essentials are present. ANS Forth is a compendium of the
> pet kludges of traditional Forthers.

What non-essentials did you have in mind?

ANS Forth was never going to be a minimalist's forth because it
had to compete with other language standards. Most criticisms
have been that more should have been included - not less.

John Doty

unread,
Jul 20, 2006, 6:13:32 PM7/20/06
to
Ed wrote:

> "John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:_sGdnQ6NMZeDxiXZ...@wispertel.com...
>
>>Ed wrote:
>>
>>
>>>With that in mind, it was appropriate ANS Forth should leave
>>>out non-essentials or things that amount to personal wishlists.
>>
>>If ANS Forth had actually done this, there would be little to criticize.
>>But many non-essentials are present. ANS Forth is a compendium of the
>>pet kludges of traditional Forthers.
>
>
> What non-essentials did you have in mind?

One tires of repeating ones self. The biggest set revolves around
interpret state and all of the extra kludges needed to support the
differences between the two states. But there are plenty more. There are
many standard words that can be trivially implemented in standard ways:
those don't belong in the standard.

> ANS Forth was never going to be a minimalist's forth because it
> had to compete with other language standards.

C trounced PL/I by being minimalist.

--

John Doty, Noqsi Aerospace, Ltd.

jeth...@gmail.com

unread,
Jul 20, 2006, 7:30:06 PM7/20/06
to

John Doty wrote:
> Ed wrote:

> > What non-essentials did you have in mind?

> The biggest set revolves around


> interpret state and all of the extra kludges needed to support the
> differences between the two states.

This is something that most Forths had in common at the time. If I
remember, the Forth that Chuck was using then was cmforth which had
interpret and compile states, though he'd come up with a new special
way to handle them.

The standard was built to deal with the limitations of the big majority
of Forths. They didn't make a standard that only new Forths could meet.
We got a whole lot of problems when Forth83 did that -- people were
faced with using their old Forths or converting to a new one, and the
community split. As far as I know nobody who stuck with Forth79 is
still using Forth, they all quit rather than go their own way or
switch. That isn't what a standard should do.

I like the possibilities I've seen with compile-only Forths this time
around. (Last time it looked limited in ways I didn't like, this time I
think I see ways around those limitations.) It could not have worked to
settle on that kind of Forth then as a portability standard.

It might work now. You could write up what you expect a Forth to do to
be compatible with you, and publish a link to it. Then if anybody cares
about portability, we have two parts -- can anybody make an ANS Forth
system behave the way you want? If so, programs written for your system
will be ANS Standard programs (with an environmental dependency). Can
anybody make a system built your way work like an ANS Forth system? If
so then you have a standard system and some standard code will run on
your system.

I'd consider the former more important for getting your approach
considered the new standard. If your code counts as standard the old
way, then other people can copy it and it might catch on. And the more
code that is obviously better your way, the more likely they are to
switch to compilers done your way. It could work.

> But there are plenty more. There are
> many standard words that can be trivially implemented in standard ways:
> those don't belong in the standard.

Why not? They can be trivially implemented. People want to use them. A
Forth is standard if it provides them in source form that can be loaded
at will. Where's the harm?

> > ANS Forth was never going to be a minimalist's forth because it
> > had to compete with other language standards.

> C trounced PL/I by being minimalist.

Trivially implemented. If you don't like a word, turn it into an editor
macro. Do a global replace on every example and you're set.

Ed

unread,
Jul 21, 2006, 12:57:49 AM7/21/06
to

"John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:aLudnW2ULZNqYiLZ...@wispertel.com...

> Ed wrote:
>
> > "John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:_sGdnQ6NMZeDxiXZ...@wispertel.com...
> >
> >>Ed wrote:
> >>
> >>
> >>>With that in mind, it was appropriate ANS Forth should leave
> >>>out non-essentials or things that amount to personal wishlists.
> >>
> >>If ANS Forth had actually done this, there would be little to criticize.
> >>But many non-essentials are present. ANS Forth is a compendium of the
> >>pet kludges of traditional Forthers.
> >
> >
> > What non-essentials did you have in mind?
>
> One tires of repeating ones self. The biggest set revolves around
> interpret state and all of the extra kludges needed to support the
> differences between the two states.

And would not alternative approaches have had their own
shortcomings or necessitated "kludges"?

Were a "perfect forth" to exist we'd all be using it long ago.
Instead, people embellish their forths with whatever they believe
to be important. That there are a multitude of forths, each
emphasizing different things seems to say it all.

I'm not against perfection, I just don't believe it's achievable :)
... or desirable.

> > ANS Forth was never going to be a minimalist's forth because it
> > had to compete with other language standards.
>
> C trounced PL/I by being minimalist.

I'd hardly call C minimalist. It has avoided supplying primitives,
instead offering complete end user functions. (BTW that's not a
criticism - C was meant to be used at a more abstract level than,
say, forth.)

Jerry Avins

unread,
Jul 21, 2006, 2:09:35 PM7/21/06
to
j2th...@cavtel.net wrote:
> John Doty wrote:


>> ... There are


>> many standard words that can be trivially implemented in standard ways:
>> those don't belong in the standard.
>
> Why not? They can be trivially implemented. People want to use them. A
> Forth is standard if it provides them in source form that can be loaded
> at will. Where's the harm?

Little harm and much benefit. Everyone using those words call them by
the same name.

...

Jerry
--
Engineering is the art of making what you want from things you can get.
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

John Doty

unread,
Jul 21, 2006, 8:40:10 PM7/21/06
to
Ed wrote:

> "John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:aLudnW2ULZNqYiLZ...@wispertel.com...
>
>>Ed wrote:
>>
>>
>>>"John Doty" <j...@whispertel.LoseTheH.net> wrote in message news:_sGdnQ6NMZeDxiXZ...@wispertel.com...
>>>
>>>
>>>>Ed wrote:
>>>>
>>>>
>>>>
>>>>>With that in mind, it was appropriate ANS Forth should leave
>>>>>out non-essentials or things that amount to personal wishlists.
>>>>
>>>>If ANS Forth had actually done this, there would be little to criticize.
>>>>But many non-essentials are present. ANS Forth is a compendium of the
>>>>pet kludges of traditional Forthers.
>>>
>>>
>>>What non-essentials did you have in mind?
>>
>>One tires of repeating ones self. The biggest set revolves around
>>interpret state and all of the extra kludges needed to support the
>>differences between the two states.
>
>
> And would not alternative approaches have had their own
> shortcomings or necessitated "kludges"?

I find no such shortcomings in the compile-only dialect I use.

>
> Were a "perfect forth" to exist we'd all be using it long ago.
> Instead, people embellish their forths with whatever they believe
> to be important. That there are a multitude of forths, each
> emphasizing different things seems to say it all.
>
> I'm not against perfection, I just don't believe it's achievable :)

> .... or desirable.

There are no universal solutions, but that's not an excuse to burden a
system with useless complexity.

>
>
>>>ANS Forth was never going to be a minimalist's forth because it
>>>had to compete with other language standards.
>>
>>C trounced PL/I by being minimalist.
>
>
> I'd hardly call C minimalist. It has avoided supplying primitives,
> instead offering complete end user functions. (BTW that's not a
> criticism - C was meant to be used at a more abstract level than,
> say, forth.)

Ever used PL/I? Compared to PL/I, C is minimalist. Of course that may
not be saying much ;-)

John Doty

unread,
Jul 22, 2006, 4:59:34 AM7/22/06
to
Jerry Avins wrote:

> j2th...@cavtel.net wrote:
>
>> John Doty wrote:
>
>
>
>>> ... There are
>>> many standard words that can be trivially implemented in standard ways:
>>> those don't belong in the standard.
>>
>>
>> Why not? They can be trivially implemented. People want to use them. A
>> Forth is standard if it provides them in source form that can be loaded
>> at will. Where's the harm?
>
>
> Little harm and much benefit. Everyone using those words call them by
> the same name.

The harm is things like the (TO IS >BODY) minefield where common
mechanisms become fragmented because everything in the standard is
opaque. When the implementation has visible consequences on the
application side of the interface it is a real disaster to allow
implementation freedom. The coder has to remember a bunch of arbitrary
rules about which words work when. In a sane implementation mistakes
here don't matter (TO and IS will be equivalent and use >BODY), but
then code that works in a sane implementation may not be portable to the
inevitable insane implementations.

Opacity in the wrong place is cancerous: last years's "Current
standings: CfV: Deferred words" thread shows how there is a perceived
need to add more kludges to the (TO IS) set.

To demand that coders be expert language lawyers is a sure way to
discourage the use of the language. That's big time harm.

How to fix? Standardize only fundamentals like >BODY. Then *publish* a
"Traditional Forth Toolkit" containing things like DEFER, VALUE, TO, and IS.

jeth...@gmail.com

unread,
Jul 22, 2006, 6:22:31 AM7/22/06
to

John Doty wrote:

> The harm is things like the (TO IS >BODY) minefield where common
> mechanisms become fragmented because everything in the standard is
> opaque. When the implementation has visible consequences on the
> application side of the interface it is a real disaster to allow
> implementation freedom. The coder has to remember a bunch of arbitrary
> rules about which words work when. In a sane implementation mistakes
> here don't matter (TO and IS will be equivalent and use >BODY), but
> then code that works in a sane implementation may not be portable to the
> inevitable insane implementations.

> How to fix? Standardize only fundamentals like >BODY. Then *publish* a


> "Traditional Forth Toolkit" containing things like DEFER, VALUE, TO, and IS.

It may have been a mistake to standardise VALUE and TO. And it may have
been an accident that DEFER and IS didn't get standardised.

The rule about >BODY is that you can depend it to work on words made
with CREATE and you can't depend on it to work with other words. Since
there's a giant variety of implementation techniques, what value do we
get from trying for portability for >BODY with : definitions? What do
you get, the address of a block of machine code? or a pointer to it, or
what? But if you CREATE the word then you can use >BODY on it. That
doesn't look arbitrary to me.

Even with VALUE defined, you can redefine it if you want and bring it
in line with >BODY . Some particular implementation might have an
efficient version, and when you redefine it you lose their
optimisation. OK, your choice. You can check whether the implementation
provides a VALUE that works the way you want and only redefine it if it
doesn't. You can write code that tests whether VALUE works the way you
want and conditionally-compile your version if it doesn't.

This is extra work for somebody. (Maybe you can find a file where
somebody has done that work for you. I dunno.) That extra work comes
because the standard tried not to say how you had to implement your
Forth. They couldn't include everybody, but they included as many
Forths as they saw how to.

"code that works in a sane implementation may not be portable to the
inevitable insane implementations."

This is inevitable. It may be unfortunate that the one thing that
noncommercial Forth programmers do most is re-implement Forth, but what
can we do about it? It may be unfortunate that each commercial Forth
vendor builds their own Forth, but at least we have a minimal standard
that they will usually conform to.

Bernd Paysan

unread,
Jul 22, 2006, 9:11:49 AM7/22/06
to
j2th...@cavtel.net wrote:
> The rule about >BODY is that you can depend it to work on words made
> with CREATE and you can't depend on it to work with other words. Since
> there's a giant variety of implementation techniques, what value do we
> get from trying for portability for >BODY with : definitions? What do
> you get, the address of a block of machine code? or a pointer to it, or
> what? But if you CREATE the word then you can use >BODY on it. That
> doesn't look arbitrary to me.

But what sense does >BODY make when applied on a : definition? The
conceptual idea behind >BODY is that you can manipulate the associated data
with a specific word class. Associated data with a : definition? There's an
associated program, no associated data.

But for VALUE and DEFER, there's an associated data. So having >BODY work on
them makes sense. When the implementer feels to optimize those, he also can
special-case his >BODY so that it works on CREATE, VALUE and DEFER.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

jeth...@gmail.com

unread,
Jul 22, 2006, 10:56:12 AM7/22/06
to

Bernd Paysan wrote:

> But what sense does >BODY make when applied on a : definition? The
> conceptual idea behind >BODY is that you can manipulate the associated data
> with a specific word class. Associated data with a : definition? There's an
> associated program, no associated data.

I've seen people use >BODY to hot-patch their code. Use >BODY to get
the first xt, and work from there to substitute xt's wherever they
want. Of course that can't be very portable.

> But for VALUE and DEFER, there's an associated data. So having >BODY work on
> them makes sense. When the implementer feels to optimize those, he also can
> special-case his >BODY so that it works on CREATE, VALUE and DEFER.

Yes. But as far as I can remember, the standard doesn't say that an
implementor has to do that. He can make >BODY not work on VALUE and
still have a standard system. Maybe it was done that way for some
system where it's hard for >BODY to point to the right address for
VALUE ? If I'm wrong about that then there isn't any problem here at
all.


Even on a system like that you can redefine VALUE so >BODY works.

George Hubert

unread,
Jul 22, 2006, 11:24:37 AM7/22/06
to

There is still one problem; TO also has to work with locals as well so
>BODY would have to return the address of the data associated with the local which would be in the local (or return) stack when the xt is a local and not the address of it's data area (which probably contains the offset into the local stack) so it would be difficult implementing TO using >BODY and ! (unless the Forth doesn't implement locals).

George Hubert

jeth...@gmail.com

unread,
Jul 22, 2006, 11:36:00 AM7/22/06
to

George Hubert wrote:

> There is still one problem; TO also has to work with locals as well so
> >BODY would have to return the address of the data associated with the local which
> would be in the local (or return) stack when the xt is a local and not the address of it's
> data area (which probably contains the offset into the local stack) so it would be difficult
> implementing TO using >BODY and ! (unless the Forth doesn't implement locals).

You're right.

So the problem with TO is using the same name for locals and for
nonlocal VALUEs. And that makes a problem for standardising VALUE .

Common practice. Hard to standardise. There are Forths that provide
both behaviors, but it was hard to require Forths to provide both
behaviors.

Ed

unread,
Jul 23, 2006, 11:27:15 PM7/23/06
to

"Bernd Paysan" <bernd....@gmx.de> wrote in message news:lpk9p3...@vimes.paysan.nom...
> [..]

> But for VALUE and DEFER, there's an associated data. So having >BODY work on
> them makes sense. When the implementer feels to optimize those, he also can
> special-case his >BODY so that it works on CREATE, VALUE and DEFER.

Some would call that a kludge - and I'd be inclined to agree.
In the case of DEFER some proposals involve use of specialised
words DEFER@ DEFER! etc. Another kludge?

The Forth Standard aims to satisfy everyone by not specifying
implementation details. But this inevitably results in a plethora
of kludge words so as existing forths won't break. Whether this
is doing Forth any good is debatable. If Forth is to be kept simple
then adopting a common implementation method will sometimes
be necessary.


Bernd Paysan

unread,
Jul 24, 2006, 11:40:13 AM7/24/06
to
Ed wrote:

>
> "Bernd Paysan" <bernd....@gmx.de> wrote in message
> news:lpk9p3...@vimes.paysan.nom...
>> [..]
>> But for VALUE and DEFER, there's an associated data. So having >BODY work
>> on them makes sense. When the implementer feels to optimize those, he
>> also can special-case his >BODY so that it works on CREATE, VALUE and
>> DEFER.
>
> Some would call that a kludge - and I'd be inclined to agree.
> In the case of DEFER some proposals involve use of specialised
> words DEFER@ DEFER! etc. Another kludge?

One that's worse. There are several possible strategies how to optimize
DEFER or VALUE, and if you choose one where these words aren't CREATE DOES>
words anymore, you need a kludge to access them. Gforth's primitive centric
approach shows that this is not necessary - we optimize DEFER even though
it still is a "traditional" DEFER when interpreted.

> The Forth Standard aims to satisfy everyone by not specifying
> implementation details. But this inevitably results in a plethora
> of kludge words so as existing forths won't break. Whether this
> is doing Forth any good is debatable. If Forth is to be kept simple
> then adopting a common implementation method will sometimes
> be necessary.

Or at least adoption of common interfaces, e.g. define that >BODY goes from
an XT to the associated data.

Ed

unread,
Jul 25, 2006, 11:02:45 PM7/25/06
to

"Bernd Paysan" <bernd....@gmx.de> wrote in message news:t76fp3-...@annette.mikron.de...

> Ed wrote:
>
> >
> > "Bernd Paysan" <bernd....@gmx.de> wrote in message
> > news:lpk9p3...@vimes.paysan.nom...
> >> [..]
> >> But for VALUE and DEFER, there's an associated data. So having >BODY work
> >> on them makes sense. When the implementer feels to optimize those, he
> >> also can special-case his >BODY so that it works on CREATE, VALUE and
> >> DEFER.
> >
> > Some would call that a kludge - and I'd be inclined to agree.
> > In the case of DEFER some proposals involve use of specialised
> > words DEFER@ DEFER! etc. Another kludge?
>
> One that's worse. There are several possible strategies how to optimize
> DEFER or VALUE, and if you choose one where these words aren't CREATE DOES>
> words anymore, you need a kludge to access them. Gforth's primitive centric
> approach shows that this is not necessary - we optimize DEFER even though
> it still is a "traditional" DEFER when interpreted.

Purists would argue this merely defers (pun) complexity to the implementor.
I'm not convinced some optimizations are worth the trouble but at least your
approach removes the complexity out of the Standard.

IMO, the Forth Standard ought to describe a self-consistent (if only virtual)
Forth model. Otherwise, it becomes a "grab bag" of contradictory ideas that
somehow have to be glued together.

An example of the latter fractured approach was vocabularies. The 'solution'
to the diverse implementations of VOCABULARY was to have a search-order
toolkit. But this was so messy that applications rarely bothered. The result
is that most forths go on to implement the ONLY ALSO extension words
(thereby making it the defacto). One wonders whether it would have been
better to have the 'extension' wordset as the core and relegate the toolkit
words to the 'extentions' (or just forget them altogether :)

Another is choice of word names. Unfamiliar names now appear in the
Standard so as not to break existing code. No matter that the code is
obsolete or the forths that once supported them long since vanished.

I don't want to paint a bleak picture of the Forth-94. By and large it was
a tremendous effort and it satisfies most people that wanted a standard.
Nevertheless there was a trend to over-compromise and it's being seen
in many of the proposals being put up today.

jeth...@gmail.com

unread,
Jul 26, 2006, 8:03:16 AM7/26/06
to
Ed wrote:

> IMO, the Forth Standard ought to describe a self-consistent (if only virtual)
> Forth model. Otherwise, it becomes a "grab bag" of contradictory ideas that
> somehow have to be glued together.

Since the ANS process required wide agreement, it couldn't help but be
a grab bag. It was only through great effort that it became as
consistent as it did.

> An example of the latter fractured approach was vocabularies. The 'solution'
> to the diverse implementations of VOCABULARY was to have a search-order
> toolkit. But this was so messy that applications rarely bothered. The result
> is that most forths go on to implement the ONLY ALSO extension words
> (thereby making it the defacto). One wonders whether it would have been
> better to have the 'extension' wordset as the core and relegate the toolkit
> words to the 'extentions' (or just forget them altogether :)

They couldn't agree on ONLY ALSO . By putting that into an optional
extension they standardised its usage without forcing it on people who
didn't want it. And if you come up with something better you can
implement it in ANS Forth and give it away with your applications.

> I don't want to paint a bleak picture of the Forth-94. By and large it was
> a tremendous effort and it satisfies most people that wanted a standard.
> Nevertheless there was a trend to over-compromise and it's being seen
> in many of the proposals being put up today.

At this point it might be useful to develop a method to classify
Forths. Each coding technique will have a range of Forths that it will
reliably run on.

Here's a start:

* Physical Constraints

Cell size
Char size
Cell/Char ratio
Alignment (can float alignment be a separate issue?)
Endian
Arithmetic (anything but 2's-complement is moslty gone except for
Chuck's stuff)

These are mostly easy to deal with. Just do a few things like using
CELLS and CHARS and sprinkle some ALIGNs etc through your code and you
can mostly ignore these issues.

If your code runs for one cell size it will mostly run unchanged with a
larger cell size. Unless you depend on overflows happening a particular
way. (I've mostly seen that in random number generators.)

If your chars aren't bytes then you have no standard way to deal with
bytes.

If you store cell-size data in Forth blocks and your cell/char ratio
doubles, then the number of cells you can put into a block is cut in
half. A block is 1024 chars. No way around it. (You could make your
blocks be 2048 characters, and just use the first half block for
everything else, if you can rewrite the system.) And if return-stack
items are not cell-size then you can't manipulate them. A whole class
of tricks people like to do won't run on those systems.

Alignment can be handled so it's no problem at all provided you write
on a system with alignment. Otherwise you get no feedback about the
times you accidentally leave it out. You need to test your code on an
aligned system if you care whether it runs right there.

You only care about endianness when you bring in data from another
system, or when you C@ data that was laid down by , or !, or @ data
that was laid down by C, or C!. You don't need to do the latter. If you
import somebody else's data in blocks or streams it might be laid out
with the other endianness and you have to be ready to switch it around.

Arithmetic issues only come up with negative numbers, they're all the
same for positive numbers. And they only come up when you do bit-wise
operations on negative numbers. Don't do that and you'll be fine.
You're never going to run a Compusys machine anyway. Chuck might do
something special but you'd be rewriting for his systems anyway, it's
nothing to worry about.

* Almost-physical constraints

Harvard Architecture
Threading method
Division
Division by zero

With a Harvard architecture you can add to a data structure at HERE
while a definition is in progress. You can unallot data that was
allotted before the latest definition. You have no access to code, all
you can do with code is EXECUTE xt's.

\ Harvard only
: FOO do-some-stuff [ HERE 16 CELLS ALLOT ] LITERAL do-more-stuff ;

\ nonHarvard only, and not all of those
CREATE FOO 12 , ] do-stuff ; FOO DUP CELL+ EXECUTE
\ ditto
: BAR DUP do-stuff ;
' OVER ' BAR >BODY !

If you don't use any fancy tricks, the threading method won't matter at
all to you. Fancy tricks that aren't very portable include

: FOO do-stuff R@ EXECUTE do-more-stuff ;

the above >BODY ! trick, etc.

Division can be floored or symmetric. Most hardware does symmetric
division, floored division is often more useful. They get exactly the
same result when both values are positive. If you know what you want
you can pick which one to use. If you take pot luck you can get some
funny results when you divide negative numbers.

Divison by zero is an issue because some sysems trap it and some don't.
Some OSes trap it and there's no way to stop them. All you can hope to
do is write your own CATCH routine that traps a -10 throw code, and
take it from there. So -- if your system lets you choose whether to
ignore division by zero or trap it, then you have the best of both
worlds. If your system ignores it you can write code to trap it with a
little effort. If you don't want it trapped and it traps it anyway,
you're stuck. Your code won't port to those systems unless you can make
sure you don't divide by zero. Or test every time and do something if
it's about to happen.

* Implementation-specific tricks

DO LOOP
colon-sys
other sys
headers
STATE
IMMEDIATE
etc

Some Forths have a separate loop stack while others put DO loop indices
on the return stack. If they're on the return stack then you can't
leave anything else on the return stack that interferes with them, and
you can't leave them on the return stack when you're done with them.
Much much more flexible to have a separate loop stack but on some
machines it's inefficient and many Forths don't do it that way.

There's a bunch of arcane stuff here, and if you know the details you
can do great ltricks that other systems either can't do at all or have
to do some other way.

Colon-sys might go on the data stack, or it might get stored somewhere,
or it might not exist. This is data that : leaves for ; to tidy up. If
it goes on the data stack, and you don't know how many cells it takes,
then you can't get access to anything that's under it on the data stack
until it's gone. On some Forths you can get around that:

>R : FOO do-something [ R> ] LITERAL do-more ;

Even if the return stack is available while interpreting, some Forths
will have a command that interprets one line of source code and stops,
this routine is called by the interpreter. If you don't R> before the
end of the line you might be returning to your data.

If everything works out just right you might be able to nest
definitions.

: FOO do-stuff AHEAD [ : BAR THEN do-more ; ;

There are lots of different ways it can go, and the way you write it
varies too. This trick might be useful. But

: BAR do-more ;
: FOO do-stuff BAR ;

almost always works.

When you compile things like IF and BEGIN they leave data that will be
handled by THEN UNTIL etc. It may be left on the data stack, and if so
you can't let any other use of the data stack interfere. If it isn't on
the data stack then you can do whatever you want with the data stack.

You can use CS-PICK to get the data left by BEGIN and do fancy loops.
You can use CS-ROLL to get other syses and do whatever unstructured
control structures you want. If the sys left by DO is the same size as
the others then you can bail out of DO loops, but remember to drop the
index values from the return stack. If colon-sys is the same size then
you can branch and loop among separate definitions. God help the guy
with 1 week Forth training who gets assigned to maintain your code.

If headers are in data space then you can access them. This saves
space, you can name routines things like Choose_a_menu_item or
DANGERWILLROBINSON and print them for the user. (Names are useful while
debugging too.) If names aren't in code space then they won't get in
the way when you do

: FOO stuff IF nextstuff ; : BAR THEN elsestuff ;

The STATE issue has been discussed to death. If you use STATE there are
various ways to do it.

DEFER GO
: ] ['] COMPILE-A-WORD [IS] GO STATE ON ;
: [ ['] INTERPRET-A-WORD [IS] GO STATE OFF ; IMMEDIATE

: GO
STATE @ IF COMPILE-A-WORD ELSE INTERPRET-A-WORD THEN ;

Those two give pretty much the same result. You choose whether to
compile.

: ] BEGIN COMPILE-WORDS AGAIN ;
: [ R> DROP ; COMPILER

This one, compiling is nested inside interpreting. The first ways, if
you build your own interpreter and you do R> DROP to get out of
compiling, you will fall out of the interpreter but you'll still be
compiling. Very subtle incompatibilities are available here.

Of course if you get rid of STATE then code which uses it won't work.
And there are various incompatible ways to get rid of it. Maybe worth
sketching them out?

We've discussed IMMEDIATE to death too. I'll mention that if you do use
IMMEDIATE the system can put the flag in the header or in the code. If
it goes in the code, what happens with a :NONAME ? It might not notice
that there's no header. It might make the last header immediate or it
might not. And what happens after DOES>? Will it make the parent
immediate or will it do something to the DOES> code? How can you
reliably make the parent immediate? Like this:

: BAR DOES> do-does-stuff ;
: FOO CREATE BAR ; IMMEDIATE

Intertwined with STATE we have multiple incompatible ways to get rid of
IMMEDIATE .

It might be possible to develop a sort of taxonomic code for Forth
systems. You could classify your Forth system according to the code.
Like, "By version 2.17 of the Forth taxonomy my Forth is a
01103201B0021.

And maybe we could classify Forth code. You could say "This code
requires a **1**2***0**2 system or a **3**2***0**2 system by version
2.17" where * is something that doesn't matter.

Then the question isn't whether your Forth or your code is standard.
The question is where does it fit into the Tree of Forth. And have you
come up with a new way to be incompatile with everything else, that
requires the tree to be split.

werty

unread,
Jul 26, 2006, 5:07:17 PM7/26/06
to

New Forth does not use STACK , it uses Locals etc . It was for
old CPU's
we used STACK .
-------------------------
It's accidental to reduce the # of WORDs .
You evolve Forth , then you try to inline lower level
stuff that is speed critical .
-------------------------------------------
New Forth has NOT ONE of the obtuse ANSI ideas !!
It has all been cleverly simplified to make it easy to RUN and easy to
figure on Modern CPU's which have 14 index registers and MegaBytes of
RAM !
You only need to appreaciate the improvements on modern
CPU's , to intuitively figure New Forth !

The New Forth i'm describing is a simplification of the old Forth
Chuck wrote in Tucson , 8 miles from my house .


C, C+ , Delphi et al are LUDDITE , a way to create work for labor
union types .
Forth will unemploy 100's of millions of h/w and s/w types .
People who dont think they are "computer" types will never again
type on KB again ... data will be entered voice and [reply] buttons.

Only computers can unemploy people at this level and so suddenly .
Overhead reduced 90% , our standard of living will triple !
Oh sorry ! You were one of those "under" skilled ?
I write Software .....
_______________________________________________________________________________________

Jeff Fox wrote:
> In the presentation that I for SVFIG I reviewed some
> of the things I had talked about in the past regarding
> the optimization of minimal instruction set Forth code. I
> presented some numbers from an analysis of code written
> over a period of a year. This will be review for many and
> new for some but I think there are several significant issues
> relating to the use of the instructions in real code and about
> which optimization techniques apply.
>
> Smaller code tends to be faster code the five bit opcodes
> that manipulate the stack are faster than those that
> do memory access including calls and returns, that's
> the idea. The following large global optimizations were observed:
>
> An optimization of about 15% was observed in code size
> and code speed due to the use of tail recursion. The
> reason the number is so large is that the shorter the
> length of factored Forth words the greater the increase
> in efficiency by saving one call and return. And it is
> important to note that the saving of one cell on the
> return stack is considered a significant optimization.
> With misc code expressed in colorforth Forth words
> averaged 1.2 lines of code which made tail recursion
> significant.
>
> An optimization of about 15% was observed due to the
> use of multiple entry points and muliple exit points for
> similar reasons to that observed from the use of
> tail recursion. It should also be noted this mechanism
> can also save the use of a cell on the return stack. Some
> compilers will hide these optimizations rather than expose
> them in the source.
>
> A global optimization of about 3% was observed in program
> size due to not having to always balance stack use
> when stack wrap can be utilized. More signficant is that the
> technique provided a local 100% optimization and increase
> in resolution in a tight timing loop due to the reduced code
> overhead. In other applications in the last year much larger
> optimization values were observed using stack wrap.
>
> Other local optimizations include the use of @a+ and !a+
> in place of a traditional phrase to achieve a local 800%
> speedup improvement and size reduction. The same
> style and technique can easily be used in ANS Forth but
> because it won't have the advantage of mapping directly
> to a five bit opcode so the optimization will not be as
> significant. But it does provide a mechanism to exploit
> auto-increment addressing modes in an instruction set.
>
> -IF, -WHILE, -UNTIL obsolete quite a long list of
> traditional words and provide considerable local
> optimization in code size and speed. -IF tends to
> be about as important as IF because it is a cheap
> and fast bit test and also useful in some math.
>
> Many traditional Forth optimizations don't apply. I used
> some of them for years in various projects with little real
> value but they can provide some amazing benchmark
> hackery. Peep-hole or pin-hole optimization techiques and
> register machine and stack in memory optimzations may
> not apply at all at times. Some sequences look like they
> should optimize away in traditional Forth implementations like:
>
> DUP DROP
>
> Presumably that code would not be written that way in
> traditional Forth, but other optimizations done by inlining
> macros might easily generate that sequence.
>
> But it may be important to note that it is not the same as null
> just as the non-destructive IF is not the same as DUP IF
> because DUP is destructive.
>
> On P21 for example:
>
> 1 2 3 4 5 6 ( 1 2 3 4 5 6 ) \ bottom of stack is 1 2 3 4
> DUP ( 2 3 4 5 6 6 ) \ bottom of stack is 2 3 4 5
> DROP ( 5 2 3 4 5 6 ) \ 2 3 4 5 repeats at bottom on drop or !
> \ example of spinning the stack backwards
>
> The consequence of this different set of important or applicable
> optimizations means that, as Mr. Moore put it, "a different style
> of coding drops out" compared to the style he used in Forth
> twenty years ago.
>
> People are often confused by the numbers reported for code
> density of well written misc code but it is not that hard to
> understand. In a recent example:
>
> : DEMO ( n1 n2 -- ) over + dup ;
>
> compiles to a single 18-bit opcode while in many other
> systems the four words "over" "+" "dup" ";" might each be
> 12-bit tokens, or 16-bit words, or 32-bit words, which in turn
> reference four routines that might be 8 bytes each or more.
> The numbers can get quite large on some Forths.
>
> Opcodes as small tokens also allows their use in tokenized
> source. In Aha the source for the code phrase in DEMO would
> be two words, one token to designate that the following source
> tokens are the same tokens as object code tokens, and one
> opcode source token. The same phrase is twelve bytes in ASCII.
>
> I think one should begin with an understanding of the
> use of the updated virtual machine MISC instruction set
> in generic machineForth coding before grappling with
> optimizations for parallel programming in SEAforth.
> In this case making assumptions based on experience
> with traditional Forth and other architectures may lead
> to the wrong conclusions about the use of Forth
> MISC opcodes. This tends to be lost on
> people who remember Forth from the 70s or 80s.
>
> If everyone already remembered all this correctly as I
> keep being told they have then excuse me for reviewing it
> again for any possible newbies.
>
> I think it is best to begin with some understanding of what
> is considered optimized code in this environment before
> progressing to an understanding of parallel programming
> techniques, ROM BIOS facilites, compiler facilities, libraries,
> front ends, IO, or the electrical characteristics that define
> SEAforth.
>
> Much of the Forth code and ideas are dangerously close
> to what people are used to in traditional and ANS Forth,
> two stacks, words, : ;
> DUP DROP OVER IF THEN etc.
>
> But the idea that these opcodes were designed and fine
> tuned to be used in a different style of Forth coding than
> what fell of of the mapping of traditional Forth to big
> desktop chips.
>
> The idea of a sea of small Forth processors is very different
> than the idea of hundreds of millions of transistors in one
> giant Wintel style processor. And naturally Forth maps
> differently to these very different environments.

werty

unread,
Jul 26, 2006, 5:19:24 PM7/26/06
to

Flag register ?!!!

STOP WRITTING NON-REENTRANT CODE !!!

and when you do learn , tell Linus T' how to make Linux reentrant ..
------------------------------------------
Other obsolete ideas ....
STATE is not needed as New Forth is always in RUN mode and since
every part of Forth OpSys KNOWS it's allways running , the code is
easy to "divert" ( reenter ) .

Todays CPU's are so fast , they define a new word between your
keystrokes !
The new Word is hooked into Dict and is runable . But it can't
perform ilegal
ops so , you trblshoot it in real time .
Locals can be AutoGenerated so you input no DATA ! In may cases
, NewForth
will fix or find a mid level that exists that will do you job , so
once again
we see an unneeded effort !
In NewForth you write very few new words as they already exist and
are fetched up and [SEE] automatically because NewForth does not work
internally in Roman text , but a new scheme
using ICONs .
New H/W ? NF has low level Icons that make it even easier to hook
unfamiliar
H/W to your PDA . ......

Interface a 2.5" HDD to PDA in 20 minutes !

ARGUE THAT !!!!


-------------------------------------------------------------------------------------------------


John Doty wrote:
> Bernd Paysan wrote:
>
> > Jeff Fox wrote:
> >
> > Thanks for the overview.


> >
> >
> >>But it may be important to note that it is not the same as null
> >>just as the non-destructive IF is not the same as DUP IF
> >>because DUP is destructive.
> >
> >

> > Yes, that's obvious. That means you can't use DUP IF if you have a full
> > stack and want to branch on the top of stack element. That's the up side:
> > you save one stack element. The cost is that you lose the destructive IF,
> > and you need to DROP the flags when you don't need them (maybe it's my
> > programming style, but that's the majority). Finally, on my code, the
> > coincidence of having a DUP IF and a full stack at the same time was zero,
> > so I reverted to a destructive IF in the two b16 variants that are used in
> > our products.
>
> Have either of you guys considered a flag *register* rather than a flag
> in the stack? I think it has some serious advantages.
>
> 1. You don't have to worry about either DUP or DROP of flags: the flag
> persists until the next test.
>
> 2. Explicit arithmetic with flag values is relatively rare, and
> "short-circuit evaluation" is often a good (and more efficient!)
> substitute anyway.
>
> 3. A persistent flag register makes it easy to return success or failure
> up through several levels of code, handling it appropritely at each
> level without stack gymnastics.
>
> Nondestructive IF seems to me to fight with the stack data flow: it
> leaves the flag blocking your other operands so you're almost always
> going to need stack gymnastics immediately after. But the need to reuse
> the flag is fairly common in my code, so a register allows me to have my
> cake and eat it too. The thing I hardly ever want is a stack of flags:
> one at a time is usually enough.
>
> --
> ---


> John Doty, Noqsi Aerospace, Ltd.

> ---
> His diagnosis of the hostility ... reflects the willful blindness of the
> invader who assures himself that the natives are only made unfriendly by
> some other provocation than his own. -Barbara W. Tuchman

rickman

unread,
Jul 26, 2006, 11:02:37 PM7/26/06
to
So what is up with your NewForth? I see that you are still talking
about it in the future tense. I guess it has not left the ground yet?

Albert van der Horst

unread,
Jul 30, 2006, 3:50:34 PM7/30/06
to
In article <lpk9p3...@vimes.paysan.nom>,

Bernd Paysan <bernd....@gmx.de> wrote:
>j2th...@cavtel.net wrote:
>> The rule about >BODY is that you can depend it to work on words made
>> with CREATE and you can't depend on it to work with other words. Since
>> there's a giant variety of implementation techniques, what value do we
>> get from trying for portability for >BODY with : definitions? What do
>> you get, the address of a block of machine code? or a pointer to it, or
>> what? But if you CREATE the word then you can use >BODY on it. That
>> doesn't look arbitrary to me.
>
>But what sense does >BODY make when applied on a : definition? The
>conceptual idea behind >BODY is that you can manipulate the associated data
>with a specific word class. Associated data with a : definition? There's an
>associated program, no associated data.

It took me a long time to realize that there are two data items
involved with a CREATE word: the body and the DOES> pointer.
On an indirect threaded Forth there is one data item involved
with a colon-word, the threaded code.
That threaded code is data can be concluded from the fact that it
need to reside in a data segment, if there are separate code and
data segments.
Of course now >BODY still makes no sense for a colon-word, because
a CREATE words data area has two fields, and >BODY specifically
selects one field that doesn't exist for a colon-word.

>--
>Bernd Paysan

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
alb...@spenarnc.xs4all.nl http://home.hccnet.nl/a.w.m.van.der.horst

Ed

unread,
Aug 1, 2006, 12:15:01 AM8/1/06
to

"j2th...@cavtel.net" <jeth...@gmail.com> wrote in message
news:1153915396.5...@b28g2000cwb.googlegroups.com...
> Ed wrote:
> [..]

> > An example of the latter fractured approach was vocabularies. The 'solution'
> > to the diverse implementations of VOCABULARY was to have a search-order
> > toolkit. But this was so messy that applications rarely bothered. The result
> > is that most forths go on to implement the ONLY ALSO extension words
> > (thereby making it the defacto). One wonders whether it would have been
> > better to have the 'extension' wordset as the core and relegate the toolkit
> > words to the 'extentions' (or just forget them altogether :)
>
> They couldn't agree on ONLY ALSO . By putting that into an optional
> extension they standardised its usage without forcing it on people who
> didn't want it. And if you come up with something better you can
> implement it in ANS Forth and give it away with your applications.

Standards exist to engender a common usage. Forth didn't have a
common way of specifying dictionary searches and it was a real
problem.

One could argue the Forth-94 'do-it-yourself' primitives only served
to further divide usage. Luckily it left the backdoor open to ONLY
ALSO which is now almost exclusively used (unlike the primitives).

Is there a need for a better scheme than ONLY ALSO ? I don't know.
If there was I suspect we should have seen it by now.

0 new messages