POSTPONEing literals?

973 views
Skip to first unread message

dxforth

unread,
Apr 27, 2021, 8:03:24 PMApr 27
to
I've found an essentially no-cost way of implementing it.
Other than the novelty of being able to write ]] 123 [[
what are the reasons/examples for having it?

Hugh Aguilar

unread,
Apr 27, 2021, 11:43:15 PMApr 27
to
My MACRO: and POST: have worked with literals for quite some time.
This is a comment from my code:
\ POST: LIT: DLIT: FLIT: "LIT: are used inside of immediate words that meta-compile.
\ This is similar to ]] but a lot better because it supports literals
\ and immediate words such as [CHAR] POSTPONE etc. that take data out of the input stream.

Why are you interested in Anton Ertl's ]] construct?
It is worthless from a technical standpoint. It was invented primarily as a workaround
for Anton Ertl's lack of disambiguifiers that Elizabeth Rather forbids him from using.
Anybody who uses ]] is just brown-nosing Anton Ertl who is brown-nosing
Elizabeth Rather --- an example of: "meta-brown-nosing" --- this is a pun, because my
MACRO: and POST: are used for meta-compiling (I explain this in case
any of the ANS-Forth cult didn't get the pun).

Note that my MACRO: and POST: are ANS-Forth code.
Your as-yet-undescribed way to POSTPONE literals is not going to be ANS-Forth.
Because of this, the ANS-Forth cult will not be interested in it.

I really doubt that anybody in the ANS-Forth cult understand meta-compiling.

dxforth

unread,
Apr 28, 2021, 1:24:48 AMApr 28
to
It may interest forth implementers that provide POSTPONE. ISTM an
oversight that POSTPONE shouldn't handle both 'words and numbers'
directly when any forth interpreter can.

A fig-style interpreter looks something like:

: interpret ( -- )
begin
bl word dup c@
while
find ?dup if
state @ if compile, else execute then
else
( c-addr) number
then ?stack
repeat drop ;

Given 'number', we can define:

: POSTPONE
?comp bl word find ?dup if
0< if compile compile then compile,
end number ; immediate

Such a POSTPONE will handle any literal that 'number' can.

\ Simple POSTPONE macro
: ]]
begin >in @ bl word count ?dup
while s" [[" compare
while >in ! [compile] postpone
repeat drop end 2drop ; immediate

Anton Ertl

unread,
Apr 28, 2021, 2:41:37 AMApr 28
to
dxforth <dxf...@gmail.com> writes:
>It may interest forth implementers that provide POSTPONE. ISTM an
>oversight that POSTPONE shouldn't handle both 'words and numbers'
>directly when any forth interpreter can.

My guess ist that POSTPONE was not specified to handle numbers because
neither [COMPILE] nor COMPILE could handle numbers, and programmers
could work around the lack of POSTPONE 123 with 123 POSTPONE LITERAL.

>A fig-style interpreter looks something like:
>
>: interpret ( -- )
> begin
> bl word dup c@
> while
> find ?dup if
> state @ if compile, else execute then
> else
> ( c-addr) number
> then ?stack
> repeat drop ;
>
>Given 'number', we can define:
>
>: POSTPONE
> ?comp bl word find ?dup if
> 0< if compile compile then compile,
> end number ; immediate

This NUMBER is pretty "smart", leaving the number on the stack in
interpret state, performing the compilation semantics of LITERAL or
2LITERAL in compile state, and also knowing that one more level of
LITERAL or 2LITERAL is needed when it's called from POSTPONE.

I guess complications like that also discouraged the Forth-94
committee from standardizing POSTPONEing numbers.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2020: https://euro.theforth.net/2020

dxforth

unread,
Apr 28, 2021, 3:05:25 AMApr 28
to
Not a problem since POSTPONE is required to postpone. The ?COMP
handles any attempt by a user to do otherwise.

>
> I guess complications like that also discouraged the Forth-94
> committee from standardizing POSTPONEing numbers.

If they considered it, surely they would have mentioned it. Their
'go to' reference was Hayes' Rochester Conference paper. Does anyone
have it? It would be interesting to know what it said.

>
> - anton
>

Anton Ertl

unread,
Apr 28, 2021, 3:47:15 AMApr 28
to
dxforth <dxf...@gmail.com> writes:
>On 28/04/2021 16:29, Anton Ertl wrote:
>> dxforth <dxf...@gmail.com> writes:
>>>Given 'number', we can define:
>>>
>>>: POSTPONE
>>> ?comp bl word find ?dup if
>>> 0< if compile compile then compile,
>>> end number ; immediate
>>
>> This NUMBER is pretty "smart", leaving the number on the stack in
>> interpret state, performing the compilation semantics of LITERAL or
>> 2LITERAL in compile state, and also knowing that one more level of
>> LITERAL or 2LITERAL is needed when it's called from POSTPONE.
>
>Not a problem since POSTPONE is required to postpone.

How does that make NUMBER perform the extra LITERAL level?

Test case:

: foo postpone 123 ; immediate
: bar foo ;
bar . \ prints 123

>> I guess complications like that also discouraged the Forth-94
>> committee from standardizing POSTPONEing numbers.
>
>If they considered it, surely they would have mentioned it. Their
>'go to' reference was Hayes' Rochester Conference paper. Does anyone
>have it? It would be interesting to know what it said.

A number of Rochester Forth Conference Proceedings have appeared in
JFAR <http://soton.mpeforth.com/flag/jfar/index.html>. There are two
papers by Hayes listed in the author index:
<http://soton.mpeforth.com/flag/jfar/authors-H.html>, but they are
unlikely to be about POSTPONE.

dxforth

unread,
Apr 28, 2021, 5:02:18 AMApr 28
to
On 28/04/2021 17:37, Anton Ertl wrote:
> dxforth <dxf...@gmail.com> writes:
>>On 28/04/2021 16:29, Anton Ertl wrote:
>>> dxforth <dxf...@gmail.com> writes:
>>>>Given 'number', we can define:
>>>>
>>>>: POSTPONE
>>>> ?comp bl word find ?dup if
>>>> 0< if compile compile then compile,
>>>> end number ; immediate
>>>
>>> This NUMBER is pretty "smart", leaving the number on the stack in
>>> interpret state, performing the compilation semantics of LITERAL or
>>> 2LITERAL in compile state, and also knowing that one more level of
>>> LITERAL or 2LITERAL is needed when it's called from POSTPONE.
>>
>>Not a problem since POSTPONE is required to postpone.
>
> How does that make NUMBER perform the extra LITERAL level?
>
> Test case:
>
> : foo postpone 123 ; immediate
> : bar foo ;
> bar . \ prints 123
>

Omit immediate :)

POSTPONE 123 is akin to postponing an immediate word; it
will execute when later encountered, rather than compile.

123 POSTPONE LITERAL isn't postponing 123; it's postponing
LITERAL and 123 happens to be on the stack when it does.
IOW you're setting up a scenario to get a desired effect.

dxforth

unread,
Apr 28, 2021, 5:30:48 AMApr 28
to
On 28/04/2021 19:02, dxforth wrote:
> On 28/04/2021 17:37, Anton Ertl wrote:
>>
>> How does that make NUMBER perform the extra LITERAL level?
>>
>> Test case:
>>
>> : foo postpone 123 ; immediate
>> : bar foo ;
>> bar . \ prints 123
>>
>
> Omit immediate :)
>
> POSTPONE 123 is akin to postponing an immediate word; it
> will execute when later encountered, rather than compile.

I'll have to concede this isn't useful. I had an example
but it turns out I had used a constant rather than a literal!

Ruvim

unread,
Apr 28, 2021, 7:09:44 AMApr 28
to
On 2021-04-28 12:02, dxforth wrote:
> On 28/04/2021 17:37, Anton Ertl wrote:
>> dxforth <dxf...@gmail.com> writes:
>>> On 28/04/2021 16:29, Anton Ertl wrote:
>>>> dxforth <dxf...@gmail.com> writes:
>>>>> Given 'number', we can define:
>>>>>
>>>>> : POSTPONE
>>>>>   ?comp bl word find ?dup if
>>>>>     0< if compile compile then compile,
>>>>>   end  number ; immediate
>>>>
>>>> This NUMBER is pretty "smart", leaving the number on the stack in
>>>> interpret state, performing the compilation semantics of LITERAL or
>>>> 2LITERAL in compile state, and also knowing that one more level of
>>>> LITERAL or 2LITERAL is needed when it's called from POSTPONE.
>>>
>>> Not a problem since POSTPONE is required to postpone.
>>
>> How does that make NUMBER perform the extra LITERAL level?
>>
>> Test case:
>>
>> : foo postpone 123 ; immediate
>> : bar foo ;
>> bar . \ prints 123
>>
>
> Omit immediate :)
>
> POSTPONE 123 is akin to postponing an immediate word; it
> will execute when later encountered, rather than compile.


There is an approach that shows (or helps to understand) how POSTPONE
should work regardless of its argument kind.


: foo postpone 123 ; immediate

: bar foo ;

1. Substitute foo in bar by the body of bar in square brackets.
<==>
: bar [ postpone 123 ] ;

2. Suppose that interpretation semantics of POSTPONE X is to *perform*
compilation semantics of X. Remember that performing compilation
semantics of X is what the text interpreter does when it encounters X in
compilation state.
<==>
: bar 123 ;


Hence,

: bar foo ;

shall be equivalent to

: bar 123 ;


--
Ruvim

Anton Ertl

unread,
Apr 28, 2021, 7:35:38 AMApr 28
to
dxforth <dxf...@gmail.com> writes:
>On 28/04/2021 17:37, Anton Ertl wrote:
>> Test case:
>>
>> : foo postpone 123 ; immediate
>> : bar foo ;
>> bar . \ prints 123
>>
>
>Omit immediate :)
>
>POSTPONE 123 is akin to postponing an immediate word;

What would be the use of that? If we would want that, we could just
leave the POSTPONE away. Also, 123 does not behave like an immediate
word in normal compilation, so why would you want that POSTPONE 123
treats it as immediate? In normal text interpretation (interpret and
compile state), the number 123 behaves like

123 constant 123 \ no immediate

BTW, the example above works in the development version of Gforth, and
that's not a bug.

>123 POSTPONE LITERAL isn't postponing 123

If POSTPONE 123 does not work, I have to write 123 POSTPONE LITERAL,
and in Gforth the result after running the code is the same:

: foo1 postpone 123 ; immediate ok
: foo2 123 postpone literal ; immediate ok
: bar1 foo1 ; ok
: bar2 foo2 ; ok
simple-see bar1
$7F447B532DA0 lit
$7F447B532DA8 #123
$7F447B532DB0 ;s ok
simple-see bar2
$7F447B532DE0 lit
$7F447B532DE8 #123
$7F447B532DF0 ;s ok

dxforth

unread,
Apr 28, 2021, 8:38:55 AMApr 28
to
On 28/04/2021 15:24, dxforth wrote:
> ...
> A fig-style interpreter looks something like:
>
> : interpret ( -- )
> begin
> bl word dup c@
> while
> find ?dup if
> state @ if compile, else execute then
> else
> ( c-addr) number
> then ?stack
> repeat drop ;
>
> Given 'number', we can define:
>
> : POSTPONE
> ?comp bl word find ?dup if
> 0< if compile compile then compile,
> end number ; immediate

That won't work per Anton's comment. POSTPONE needs to know the compiling
literal used by 'number'. Here are the tweaks:

0 value nlit \ xt of the literal used by NUMBER

: number ( c-addr -- | d|n|r )
...
2dup number? if
2nip dpl @ 0< if
drop ['] literal
else
['] 2literal
then to nlit true
else
fnumber \ defer for floats
then
...
( flag) ?defined \ 0 = fail & abort
state @ if nlit execute then ;

: POSTPONE
?comp bl word find ?dup if
0< if compile compile then
else number nlit then compile, ; immediate

\\ test

DX-Forth 4.45 2021-04-17

: foo postpone 123 : immediate LITERAL is system ok
: bar foo ; ok
bar . 123 ok
: foo2 postpone 123e : immediate FLITERAL is system ok
: bar2 foo2 ; ok
bar2 f. 123. ok

dxforth

unread,
Apr 28, 2021, 10:04:32 AMApr 28
to
Result is ambiguous (POSTPONE inside brackets).

Ruvim

unread,
Apr 28, 2021, 11:28:28 AMApr 28
to
It isn't a real code, it's a pseudo code, a conceptual model. And in any
case, the result is not ambiguous since the item 2 describes semantics
for POSTPONE inside brackets (i.e., the interpretation semantics for
POSTPONE). If it would be a real code, POSTPONE should be just redefined
to have these interpretation semantics. In one my framework (standard
compliant) this looks like the following:

: postpone
state @ if postpone postpone exit then
parse-lexeme ['] translate-lexeme execute-compiling ?nf
; immediate

\ If you want to go deeper:
\ translate-lexeme ( i*x sd-lexeme -- j*x flag )
\ -- https://git.io/J3Tkf
\ execute-compiling ( i*x xt -- j*x )
\ -- https://git.io/J3Tk5

dxforth

unread,
Apr 28, 2021, 10:01:25 PMApr 28
to
On 28/04/2021 22:38, dxforth wrote:
> ...
> POSTPONE needs to know the compiling
> literal used by 'number'. Here are the tweaks:

We can improve on that as nlit wasn't needed after all.
'number' now returns the xt directly.

: number ( c-addr -- [d|n|r] xt )
...
2dup number? if
2nip dpl @ 0< if
drop ['] literal
else
['] 2literal
then true
else
fnumber \ defer for floats
then
...
( flag) ?defined \ 0 = fail & abort
>r state @ if r@ execute then r> ;

: POSTPONE
?comp bl word find ?dup if
0< if compile compile then
else number then compile, ; immediate

'number' in INTERPRET will need to drop the xt:

: interpret ( -- )
begin
bl word dup c@
while
find ?dup if
state @ if compile, else execute then
else
( c-addr) number DROP
then ?stack
repeat drop ;

What was the cost of making POSTPONE handle numeric literals?
Comparing the old and new DX-Forth executables, it was an
extra 16 bytes.

\ tests

azathot...@gmail.com

unread,
Apr 28, 2021, 10:14:33 PMApr 28
to
Hugh do you have an online forth tutorial?
ARe you able to do dynamic web sites in forth?

dxforth

unread,
Apr 28, 2021, 10:30:38 PMApr 28
to
This guy can:

https://www.45office.com/

Anton Ertl

unread,
Apr 29, 2021, 2:27:32 AMApr 29
to
Or, instead of making NUMBER state-smart, you put the STATE handling
in INTERPRET:

Replace the last line of NUMBER with ";"

Define INTERPRET as:

: interpret ( -- )
begin
bl word dup c@
while
find ?dup if
state @ if compile, else execute then
else
( c-addr) number state @ if execute else drop then
then ?stack
repeat drop ;

And POSTPONE as:

: POSTPONE
bl word find ?dup if
0< if compile compile then
else number dup >r execute r> then compile, ; immediate

This POSTPONE is not STATE-"smart".

dxforth

unread,
Apr 29, 2021, 3:25:05 AMApr 29
to
Would you have an example of use where it would matter? POSTPONE
COMPILE LITERAL etc are either legally or technically compile-only.

none albert

unread,
Apr 29, 2021, 5:13:02 AMApr 29
to
In article <2021Apr2...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
<SNIP>
>
>Or, instead of making NUMBER state-smart, you put the STATE handling
>in INTERPRET:
>
>Replace the last line of NUMBER with ";"
>
>Define INTERPRET as:
>
>: interpret ( -- )
> begin
> bl word dup c@
> while
> find ?dup if
> state @ if compile, else execute then
> else
> ( c-addr) number state @ if execute else drop then
> then ?stack
> repeat drop ;

Or, if `` number '' is handled by immediate prefixes you can just
leave the else part.
Note that prefixes like $ # % ' presort the different cases of numbers
to handle. ( $1234 #200 %10011100 'A' )

Or if INTERPRET monitors stack changes, all cases of `` number ''
would be simplified.

>
>And POSTPONE as:
>
>: POSTPONE
> bl word find ?dup if
> 0< if compile compile then
> else number dup >r execute r> then compile, ; immediate
>
>This POSTPONE is not STATE-"smart".

It is IMMEDIATE-"smart" , but that is less objectionable.

>- anton

Groetjes Albert
--
"in our communism country Viet Nam, people are forced to be
alive and in the western country like US, people are free to
die from Covid 19 lol" duc ha
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Anton Ertl

unread,
Apr 29, 2021, 5:14:09 AMApr 29
to
dxforth <dxf...@gmail.com> writes:
>> This POSTPONE is not STATE-"smart".
>
>Would you have an example of use where it would matter?

: postpone postpone postpone ; immediate
: foo [ postpone . ] ; immediate

>POSTPONE
>COMPILE LITERAL etc are either legally or technically compile-only.

"Compile-only" is used in two different meanings:

1) Has undefined interpretation semantics.

2) Errors out when being run in interpret state.

The fixed POSTPONE is technically fine wrt either meaning: it has
interpretation semantics, and it does not produce error when it runs
in interpret state

Concerning "legally", the standard only specifies 1) for POSTPONE, and
that is easily fixed:

: postpone postpone postpone ; immediate

Apart from that, given all the slavery and freedom rethoric you have
been using wrt standard compliance, don't you want to provide the
dxforth programmers with the freedom to just write

: foo [ postpone . ] ;

Gforth, SwiftForth, and VFX provide this freedom.

Ruvim

unread,
Apr 29, 2021, 7:09:43 AMApr 29
to
On 2021-04-29 11:54, Anton Ertl wrote:
> dxforth <dxf...@gmail.com> writes:
>>> This POSTPONE is not STATE-"smart".
>>
>> Would you have an example of use where it would matter?
>
> : postpone postpone postpone ; immediate
> : foo [ postpone . ] ; immediate

It's ambiguous. It should be admitted, at the moment the standard
doesn't allow to perform compilation semantics in interpretation state.

But in any standard system, POSTPONE can be redefined in such a way that
your test will work as expected:

: postpone ( -- ) \ "name"
bl word find dup 0= if -13 throw then
swap postpone literal
1 = if ['] execute-compiling else ['] compile, then compile,
; immediate



--
Ruvim

dxforth

unread,
Apr 29, 2021, 7:48:29 AMApr 29
to
On 29/04/2021 18:54, Anton Ertl wrote:
>
>>> This POSTPONE is not STATE-"smart".

I agree your mods correct the oddity of NUMBER doing work that is
properly the function of INTERPRET and POSTPONE. I'll be retaining
?COMP which in my actual code is positioned just before NUMBER in
POSTPONE. That's because my COMPILE already has ?COMP built-in for
crash prevention.

>>
>>Would you have an example of use where it would matter?
>
> : postpone postpone postpone ; immediate
> : foo [ postpone . ] ; immediate
>
>>POSTPONE
>>COMPILE LITERAL etc are either legally or technically compile-only.
>
> "Compile-only" is used in two different meanings:
>
> 1) Has undefined interpretation semantics.
>
> 2) Errors out when being run in interpret state.
>
> The fixed POSTPONE is technically fine wrt either meaning: it has
> interpretation semantics, and it does not produce error when it runs
> in interpret state
>
> Concerning "legally", the standard only specifies 1) for POSTPONE, and
> that is easily fixed:
>
> : postpone postpone postpone ; immediate
>
> Apart from that, given all the slavery and freedom rethoric you have
> been using wrt standard compliance, don't you want to provide the
> dxforth programmers with the freedom to just write
>
> : foo [ postpone . ] ;
>
> Gforth, SwiftForth, and VFX provide this freedom.
>

200x doesn't and the principals of those systems have been sitting on
its board since inception. If anyone is being disenfranchised, it
would appear to be 200x users.

dxforth

unread,
Apr 29, 2021, 7:47:54 PMApr 29
to
On 29/04/2021 21:09, Ruvim wrote:
> On 2021-04-29 11:54, Anton Ertl wrote:
>> dxforth <dxf...@gmail.com> writes:
>>>> This POSTPONE is not STATE-"smart".
>>>
>>> Would you have an example of use where it would matter?
>>
>> : postpone postpone postpone ; immediate
>> : foo [ postpone . ] ; immediate
>
> It's ambiguous. It should be admitted, at the moment the standard
> doesn't allow to perform compilation semantics in interpretation state.

Has the case been made that it should? That something now works
that previously didn't is a curiosity - not a demonstrated need.
The functionality described above can almost certainly be duplicated
by other means. I just haven't been able to find the many examples
of use that would justify changing POSTPONE to do it. Why I asked.
The same for POSTPONEing literals. I've just spent 21 bytes on
something I don't know I'll ever use. When forth's hacks start
thinking like Moore, the language may gain some credibility but
not until then.

Ruvim

unread,
Apr 30, 2021, 7:15:15 AMApr 30
to
So the question is why do we have (or why do we need to provide) some
features that are very rarely used and have the alternatives?

I see this problem as a problem of integrality and consistency.

A user expects that the system/language is (or should be) integral and
consistent. A user mentally builds a model of the system, and this model
allows to predict the system's behavior in edge case, or to extrapolate
behavior from one set of situations into another set.

If some prediction fails, the reason should be sound, convincing, and
clear to correct the model. Otherwise it will look like a bug or a flaw.



If POSTPONE works for words, why it cannot work for numbers? What is a
sound reason for that? Does it have some intrinsic uncertainty? Is it
difficult to implement?

If nothing of that, it's better to not break a more general model and
support applying POSTPONE to numbers.




Ditto about performing compilation semantics in interpretation state.
If a user (a program) explicitly directs a system to perform some
compilation semantics, why he should be concerned to also set
compilation state? The system can set compilation state by itself. It's
not difficult. And all required information is available for the system.

A small nuance is that the system should not revert the state if it was
explicitly directed to change the state. But it's also a simple thing,
see my the same example https://git.io/J3331


So there is no any sound reason to break (i.e. to not support) a more
general model.


--
Ruvim

none albert

unread,
Apr 30, 2021, 7:43:16 AMApr 30
to
Your reasoning is sound. My conclusion is that with the kind of
abstraction POSTPONE offers we took a wrong turn. Instead of supporting
POSTPONE for numbers, I want to get rid of POSTPONE altogether.

>--
>Ruvim

Ruvim

unread,
Apr 30, 2021, 11:52:46 AMApr 30
to
What makes you think so?


> Instead of supporting POSTPONE for numbers,
> I want to get rid of POSTPONE altogether.

But then you have to get rid something from FIND [ ] and COMPILE,
since otherwise POSTPONE can be implemented using these words.

So, do you want to lock the metaprogramming capabilities, or just
suggest a better alternative to POSTPONE like like "c{ ... }c" construct?


--
Ruvim

none albert

unread,
Apr 30, 2021, 4:20:03 PMApr 30
to
In article <s6h94c$1s7$1...@dont-email.me>, Ruvim <ruvim...@gmail.com> wrote:
>On 2021-04-30 14:43, albert wrote:
>> In article <s6gos1$7jf$1...@dont-email.me>, Ruvim <ruvim...@gmail.com> wrote:
<SNIP>
>> Your reasoning is sound. My conclusion is that with the kind of
>> abstraction POSTPONE offers we took a wrong turn.
>
>What makes you think so?

I need more time reading all the discussions about POSTPONE than I
have ever spent in using it.

>
>
>> Instead of supporting POSTPONE for numbers,
>> I want to get rid of POSTPONE altogether.
>
>But then you have to get rid something from FIND [ ] and COMPILE,
>since otherwise POSTPONE can be implemented using these words.
>
>So, do you want to lock the metaprogramming capabilities, or just
>suggest a better alternative to POSTPONE like like "c{ ... }c" construct?

There is one meta programming facility in lucky thus far.

{ _does ! _build ! '{ RUN 'NAME , 'DEA , 'dodoe , 'SWAP , '>CFA , '! ,
_does @ 'LITERAL RUN '>DFA , '@ , ', , _build @ , '} RUN : } : META

An immediate word is "postpone"d 1) by e.g.
'{ RUN
and a word is compiled by e.g.
'SWAP ,

-All words have one behaviour.
-If you meta compile you have to look up immediacy
- , is approximately COMPILE, and RUN is approximately EXECUTE
- For literals just use good old LITERAL

POSTPONE saves you from looking up immediacy, that is not worth it
in my book.

>--
>Ruvim

1) Actually it is not postponed, it is run immediately.

dxforth

unread,
Apr 30, 2021, 10:48:19 PMApr 30
to
I imagine a new user wants a concise, easily comprehended, language that
lets them do what needs to be done. Fooling compilers into doing weird
and wonderful things is one thing, but arguing entitlement another.

I wouldn't have a clue what the postpone/foo example shown above is meant
to do (and I'm supposed to know forth). In extending POSTPONE to handle
literals one might argue it's simple to understand, less clumsy than
POSTPONE LITERAL et al and costs little to implement. It's something that
could - possibly should - have been incorporated into POSTPONE from the
beginning, had someone thought of it. Can Standard Forth and users get by
without it? I imagine they can.

Ruvim

unread,
May 1, 2021, 10:18:14 AMMay 1
to
On 2021-04-30 23:17, albert wrote:
> In article <s6h94c$1s7$1...@dont-email.me>, Ruvim <ruvim...@gmail.com> wrote:
>> On 2021-04-30 14:43, albert wrote:
>>> In article <s6gos1$7jf$1...@dont-email.me>, Ruvim <ruvim...@gmail.com> wrote:
> <SNIP>
>>> Your reasoning is sound. My conclusion is that with the kind of
>>> abstraction POSTPONE offers we took a wrong turn.
>>
>> What makes you think so?
>
> I need more time reading all the discussions about POSTPONE than I
> have ever spent in using it.
>
>>
>>
>>> Instead of supporting POSTPONE for numbers,
>>> I want to get rid of POSTPONE altogether.
>>
>> But then you have to get rid something from FIND [ ] and COMPILE,
>> since otherwise POSTPONE can be implemented using these words.
>>
>> So, do you want to lock the metaprogramming capabilities, or just
>> suggest a better alternative to POSTPONE like like "c{ ... }c" construct?
>
> There is one meta programming facility in lucky thus far.
>
> { _does ! _build ! '{ RUN 'NAME , 'DEA , 'dodoe , 'SWAP , '>CFA , '! ,
> _does @ 'LITERAL RUN '>DFA , '@ , ', , _build @ , '} RUN : } : META


I see. It seems, it can be refactored as the following:

{ 'LITERAL RUN } : LIT,

{ _does ! _build ! '{ RUN { NAME DEA dodoe SWAP >CFA ! } ,
_does @ LIT, { >DFA @ , } , _build @ , '} RUN : } : META:


Or an even better variant:

\ If the control flow stack is separated from the data stack
{ ( xt1 -- xt2 ) '{ RUN RUN '} RUN } : DEF-BY

\ If the control flow stack is not separated
{ ( xt1 -- xt2 ) '{ RUN-EFFECT N>R RUN NR> DROP '} RUN } : DEF-BY


{ ( xt-build xt-does )
{ { NAME DEA dodoe SWAP >CFA ! } , LIT, { >DFA @ , } , , } DEF-BY
} : META

\ Usage:
\ { ...build } { ...does } META : X:


> An immediate word is "postpone"d 1) by e.g.
> '{ RUN
> and a word is compiled by e.g.
> 'SWAP ,
>
> -All words have one behaviour.
> -If you meta compile you have to look up immediacy
> - , is approximately COMPILE, and RUN is approximately EXECUTE
> - For literals just use good old LITERAL
>
> POSTPONE saves you from looking up immediacy, that is not worth it
> in my book.


Is it possible to define the word P in such a way that

'{ P 'NAME P

is equivalent to

'{ RUN 'NAME ,

?

Or maybe the prefix P: that

P:{ P:NAME

is equivalent to

'{ RUN 'NAME ,

?



> 1) Actually it is not postponed, it is run immediately.

But it's running is postponed!


--
Ruvim

Ruvim

unread,
May 2, 2021, 3:02:43 AMMay 2
to
Agreed.


> I wouldn't have a clue what the postpone/foo example shown above is meant
> to do (and I'm supposed to know forth).

By common expectations, the following definition of foo

: p postpone postpone ; immediate \ (1)
: foo [ p . ] ; immediate \ (2)

should be equivalent to

: foo p . ; immediate \ (3)

that is equivalent to

: foo postpone . ; immediate \ (4)

That is equivalent to

: foo ['] . compile, ; immediate \ (5)

since "." (Dot) is an ordinary word.


By definition (1), ES(p) is to perform CS(postpone).

The problem is that in the point (2) the program performs ES(p) in
interpretation state, that means it performs CS(postpone) in
interpretation state, and it is ambiguous. A standard program is not
allowed to perform CS in interpretation state.

Nevertheless, the expectation that a system can properly handle this
case is very sound. The system knows that it's directed to performs CS
(since they were appended via POSTPONE), and thus the system can set
compilation state by themself to perform these semantics.




> In extending POSTPONE to handle
> literals one might argue it's simple to understand, less clumsy than
> POSTPONE LITERAL et al and costs little to implement.  It's something that
> could - possibly should - have been incorporated into POSTPONE from the
> beginning, had someone thought of it.  Can Standard Forth and users get by
> without it?  I imagine they can.

Of course they can. Moreover, it's possible to redefine POSTPONE to
handle literals. Moreover, the major part of the standard words can be
implemented via the rest part, so users can get by without the former part.

The question is in a criterion — what is worth standardizing, and what
isn't.



--
Ruvim

none albert

unread,
May 2, 2021, 7:16:12 AMMay 2
to
I invented this system to simplify things.
So { } is supposed to be used in pairs, even if it is
'{ RUN ..... '} RUN
If you don't comply, the warranty stops.

>
>Or maybe the prefix P: that
>
> P:{ P:NAME
>
>is equivalent to
>
> '{ RUN 'NAME ,

A prefix that postpones? It tries to be clever like postpone
and I'm against it. It was the cleverness (IMMEDIATE-smartness)
that I'm railing against.

>
>?
>
>
>
>> 1) Actually it is not postponed, it is run immediately.
>
>But it's running is postponed!
>
>
>--
>Ruvim

dxforth

unread,
May 3, 2021, 12:58:34 AMMay 3
to
On 2/05/2021 17:02, Ruvim wrote:
> ...
> Nevertheless, the expectation that a system can properly handle this
> case is very sound. The system knows that it's directed to performs CS
> (since they were appended via POSTPONE), and thus the system can set
> compilation state by themself to perform these semantics.

It may be your expectation. (2) fails on my system. I get certain
advantages continuing to use a POSTPONE that's based on COMPILE and
thus far none using POSTPONE in immediate mode - which has always
been counter-intuitive.

>
>> In extending POSTPONE to handle
>> literals one might argue it's simple to understand, less clumsy than
>> POSTPONE LITERAL et al and costs little to implement.  It's something that
>> could - possibly should - have been incorporated into POSTPONE from the
>> beginning, had someone thought of it.  Can Standard Forth and users get by
>> without it?  I imagine they can.
>
> Of course they can. Moreover, it's possible to redefine POSTPONE to
> handle literals.

Not easily I presume?

> Moreover, the major part of the standard words can be
> implemented via the rest part, so users can get by without the former part.
>
> The question is in a criterion — what is worth standardizing, and what
> isn't.

The committee decides that. You make the choice whether you can use
it or not.

Ruvim

unread,
May 3, 2021, 4:52:11 AMMay 3
to
On 2021-05-03 07:58, dxforth wrote:
> On 2/05/2021 17:02, Ruvim wrote:
>> ...
>> Nevertheless, the expectation that a system can properly handle this
>> case is very sound. The system knows that it's directed to performs CS
>> (since they were appended via POSTPONE), and thus the system can set
>> compilation state by themself to perform these semantics.
>
> It may be your expectation.

Yes, such behavior from a Forth system is expected by me. But not only
me. It seems to me the majority of the users have the same expectation.
And one of the reason that people have so many discussion concerning
POSTPONE is that this expectation is not met, I believe.


> (2) fails on my system.

At the moment such fail is compliant with the standard.

BTW, in the Anton's edition you system will pass (2) in this particular
case (i.e., it will meet the expectation when POSTPONE is argument of
POSTPONE). But it doesn't have much sense, since in many other cases the
system will still not meet this expectation.



> I get certain advantages continuing to use a POSTPONE that's based
> on COMPILE and thus far none using POSTPONE in immediate mode - which
> has always been counter-intuitive.

Please take a note that in (2) POSTPONE is not used in immediate mode!
But only its compilation semantics are indirectly performed. It means
that even if interpretation semantics would be specified/defined for
POSTPONE, they are not taken into account in (2), according the
mentioned expectation.



>>> In extending POSTPONE to handle
>>> literals one might argue it's simple to understand, less clumsy than
>>> POSTPONE LITERAL et al and costs little to implement.  It's something
>>> that could - possibly should - have been incorporated into POSTPONE
>>> from the beginning, had someone thought of it.  Can Standard Forth and
>>> users get by without it? I imagine they can.
>> Of course they can. Moreover, it's possible to redefine POSTPONE to
>> handle literals.
>
> Not easily I presume?

If you have recognizers for numbers — it's very easy.

Even implementing standard POSTPONE via FIND from the scratch (in a
portable manner) is possible and quite easy.

Could you test this implementation in your system: https://git.io/J30D6


It's surprising how many systems provide broken FIND.



>>
>> The question is in a criterion — what is worth standardizing, and what
>> isn't.
>
> The committee decides that.  You make the choice whether you can use
> it or not.

Well, then even if users can get by without something, it isn't an
argument to not standardize this thing.

And the committee should also have some criteria or at least grounds.


--
Ruvim

Hugh Aguilar

unread,
May 3, 2021, 10:44:41 PMMay 3
to
On Monday, May 3, 2021 at 1:52:11 AM UTC-7, Ruvim wrote:
> Even implementing standard POSTPONE via FIND from the scratch (in a
> portable manner) is possible and quite easy.

This is not possible in ANS-Forth without the disambiguifiers already available
because FIND is ambiguous (sometimes fails completely) for about 51 words
in ANS-Forth. This is described here:
https://groups.google.com/g/comp.lang.forth/c/T-yYkpVwYew/m/C6uvd8djAgAJ
Ironically however, disambiguifiers are defined using POSTPONE --- so you can't
define POSTPONE on the assumption that the disambiguifiers are already available.

I don't think Ruvim knows any more about ANS-Forth than Stephen Pelc does,
which is nothing.

dxforth

unread,
May 4, 2021, 12:20:24 AMMay 4
to
On 3/05/2021 18:52, Ruvim wrote:
> On 2021-05-03 07:58, dxforth wrote:
>
>>>> In extending POSTPONE to handle
>>>> literals one might argue it's simple to understand, less clumsy than
>>>> POSTPONE LITERAL et al and costs little to implement.  It's something
>>>> that could - possibly should - have been incorporated into POSTPONE
>>>> from the beginning, had someone thought of it.  Can Standard Forth and
>>>> users get by without it? I imagine they can.
>>> Of course they can. Moreover, it's possible to redefine POSTPONE to
>>> handle literals.
>>
>> Not easily I presume?
>
> If you have recognizers for numbers — it's very easy.
>
> Even implementing standard POSTPONE via FIND from the scratch (in a
> portable manner) is possible and quite easy.
>
> Could you test this implementation in your system: https://git.io/J30D6

Compiling your definition of POSTPONE under VFX causes it to fails
when attempting:

: OF POSTPONE OVER POSTPONE = POSTPONE IF POSTPONE DROP ; IMMEDIATE

: TEST 2 OF ." two " ELSE . THEN ;

Which is the problem I encountered attempting a 'portable' POSTPONE
based on my expectations.

dxforth

unread,
May 4, 2021, 1:12:09 AMMay 4
to
There's certainly limits to what one can expect from a Standard.

Ruvim

unread,
May 4, 2021, 1:33:49 AMMay 4
to
My implementation is only portable among the standard systems that
provide the words that are used.

FVX provides the broken (non standard compliant) "COMPILE," word.

: test-if
c" if" find dup 0= if ." unfound" 2drop exit then
1 = if ." executed" execute else ." compiled" compile, then
; immediate

] test-if [ .s

This test prints "compiled" and leave two numbers on the stack.

It's non standard. "COMPILE," shall have the stack effect ( xt -- )


--
Ruvim

Ruvim

unread,
May 4, 2021, 7:09:15 AMMay 4
to
Regardless of this issue, "compile," doesn't return the consistent
values during compilation "if" (as an example).

The two following definitions shall be equivalent to "if" word when this
word is encountered by the Forth text interpreter.

: if-via-eval s" if" evaluate ; immediate

: if-via-find c" if" find dup 0= -13 and throw
state @ if dup -1 = if drop compile, exit then then drop execute
; immediate

It means that in any program we can replace "if" (that is not an
argument of any other word, like "postpone") by "if-via-eval" or
"if-via-find" and the results shall be the same.

Thus the following definitions for "foo" and "bar" should produce the
same results too.

: foo if-via-eval -1 else 0 then ;
t{ 1 foo 0 foo -> -1 0 }t

: bar if-via-find -1 else 0 then ;
t{ 1 bar 0 bar -> -1 0 }t

But compilation of "bar" produces error -22 "Control structure
mismatch", since "compile," leaves an excessive value that is not
consumed by else/then.

If we remove this excessive value, the code works correctly:

: bar if-via-find [ .s cr nip ] -1 else 0 then ;
1 bar . \ prints "-1"
0 bar . \ prints "0"



--
Ruvim

Stephen Pelc

unread,
May 5, 2021, 5:40:50 AMMay 5
to
On Tue, 4 May 2021 14:20:20 +1000, dxforth <dxf...@gmail.com> wrote:

>Compiling your definition of POSTPONE under VFX causes it to fails
>when attempting:
>
>: OF POSTPONE OVER POSTPONE = POSTPONE IF POSTPONE DROP ; IMMEDIATE
>
>: TEST 2 OF ." two " ELSE . THEN ;

Compiles fine on both 32 bit and 64 bit versions of the current v5.11.

dis test
TEST
( 000E5F70 4883FB02 ) CMP RBX, # 02
( 000E5F74 0F851B000000 ) JNZ/NE 000E5F95
( 000E5F7A 488B5D00 ) MOV RBX, [RBP]
( 000E5F7E 488D6D08 ) LEA RBP, [RBP+08]
( 000E5F82 E8E180F3FF ) CALL 0001E068 (.") "two "
( 000E5F90 E905000000 ) JMP 000E5F9A
( 000E5F95 E8DE76F3FF ) CALL 0001D678 .
( 000E5F9A C3 ) RET/NEXT
( 43 bytes, 8 instructions )
ok


Stephen

--
Stephen Pelc, ste...@vfxforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, +44 (0)78 0390 3612, +34 649 662 974
web: http://www.mpeforth.com - free VFX Forth downloads

Stephen Pelc

unread,
May 5, 2021, 6:14:49 AMMay 5
to
On Tue, 4 May 2021 08:33:46 +0300, Ruvim <ruvim...@gmail.com>
wrote:

>My implementation is only portable among the standard systems that
>provide the words that are used.
>
>FVX provides the broken (non standard compliant) "COMPILE," word.
>
> : test-if
> c" if" find dup 0= if ." unfound" 2drop exit then
> 1 = if ." executed" execute else ." compiled" compile, then
> ; immediate
>
> ] test-if [ .s
>
>This test prints "compiled" and leave two numbers on the stack.
>
>It's non standard. "COMPILE," shall have the stack effect ( xt -- )

It's perfectly fine. Under VFX, IF is NDCS and non-immediate. COMPILE,
executes the compilation behaviour, which as for many versions of IF
returns an address to patch during compilation.

If you want these tests to behave correctly, you actually have
to test an IF ... THEN pair and check stack actions a bit more
carefully.

Anton Ertl

unread,
May 5, 2021, 7:58:26 AMMay 5
to
ste...@mpeforth.com (Stephen Pelc) writes:
>On Tue, 4 May 2021 08:33:46 +0300, Ruvim <ruvim...@gmail.com>
>wrote:
>>FVX provides the broken (non standard compliant) "COMPILE," word.
>>
>> : test-if
>> c" if" find dup 0= if ." unfound" 2drop exit then
>> 1 = if ." executed" execute else ." compiled" compile, then
>> ; immediate
>>
>> ] test-if [ .s
>>
>>This test prints "compiled" and leave two numbers on the stack.
>>
>>It's non standard. "COMPILE," shall have the stack effect ( xt -- )
>
>It's perfectly fine. Under VFX, IF is NDCS and non-immediate. COMPILE,
>executes the compilation behaviour, which as for many versions of IF
>returns an address to patch during compilation.

The standard stack effect of COMPILE, is ( xt -- ). If COMPILE,
behaves differently on your system, it's non-standard. I reported
this bug to you in 2015
<2015100907...@a4.complang.tuwien.ac.at>. I had the
impression that you would fix it in VFX 5, but given your reaction,
this is now questionable; I work at a university, so I cannot test VFX
5 myself.

Ruvim

unread,
May 5, 2021, 8:11:43 AMMay 5
to
On 2021-05-05 13:14, Stephen Pelc wrote:
> On Tue, 4 May 2021 08:33:46 +0300, Ruvim <ruvim...@gmail.com>
> wrote:
>
>> My implementation is only portable among the standard systems that
>> provide the words that are used.
>>
>> FVX provides the broken (non standard compliant) "COMPILE," word.
>>
>> : test-if
>> c" if" find dup 0= if ." unfound" 2drop exit then
>> 1 = if ." executed" execute else ." compiled" compile, then
>> ; immediate
>>
>> ] test-if [ .s
>>
>> This test prints "compiled" and leave two numbers on the stack.
>>
>> It's non standard. "COMPILE," shall have the stack effect ( xt -- )
>
> It's perfectly fine. Under VFX, IF is NDCS and non-immediate. COMPILE,
> executes the compilation behaviour, which as for many versions of IF
> returns an address to patch during compilation.


Perhaps it's fine for VFX, but I can't agree it's standard compliant.

| COMPILE,
| Interpretation: Interpretation semantics for this word are undefined.
| Execution: ( xt -- )
| Append the execution semantics of the definition represented
| by xt to the execution semantics of the current definition.

Appending execution semantics cannot have any other side effects, except
specified here.

"COMPILE," is not allowed to perform compilation semantics for IF.



It's similar to POSTPONE

| Compilation: ( "<spaces>name" -- )
| Skip leading space delimiters. Parse name delimited by a space.
| Find name. Append the compilation semantics of name to the
| current definition. An ambiguous condition exists if name
| is not found.

POSTPONE just appends compilation semantics, and doesn't have any other
side effects on the stacks.



> If you want these tests to behave correctly, you actually have
> to test an IF ... THEN pair and check stack actions a bit more
> carefully.

I suppose you already notice, I did that.


--
Ruvim

dxforth

unread,
May 5, 2021, 9:04:45 AMMay 5
to
A less problematic test might be:

: test test-if ." non-zero" then ;

This fails on VFX. But was it reasonable? I doubt it - just as
redefining POSTPONE and expecting it to work on every system wasn't
reasonable. Only a TC can declare what is standard - so ask them.

Stephen Pelc

unread,
May 5, 2021, 10:37:54 AMMay 5
to
On Wed, 05 May 2021 11:46:26 GMT, an...@mips.complang.tuwien.ac.at
(Anton Ertl) wrote:

>The standard stack effect of COMPILE, is ( xt -- ). If COMPILE,
>behaves differently on your system, it's non-standard. I reported
>this bug to you in 2015
><2015100907...@a4.complang.tuwien.ac.at>.

NDCS = non default compilation semantics, e.g. IF

And that's probably what triggered my NDCS esploration. The base
problem comes from the standard's definitions of words. There are
three cases:
1) normal words
2) immediate words
3) NDCS words

The standard only says how to handle cases 1) and 2). So the answer
to Ruvim's problem is "Don't do that".

Until the standard encompasses NDCS words, the standard is incomplete.
The standard deliberately does not mandate implementation techniques
and VFX uses a technique for NDCS words that is useful, but breaks
careless tests. The EuroForth papers are there to read, and nobody has
said that my analysis is wrong.

My conclusion from all this is that the standard has a bug in it.
Unfortunately, fixing the bug will be a real pain.

> I had the
>impression that you would fix it in VFX 5, but given your reaction,
>this is now questionable; I work at a university, so I cannot test VFX
>5 myself.

It is fixed. The standard is broken. You can test it, I hereby give
you and other educators an exemption for university use. The licence
will change for university educators in due course. As you well know,
you only had to ask.

Anton Ertl

unread,
May 5, 2021, 10:39:47 AMMay 5
to
dxforth <dxf...@gmail.com> writes:
>Only a TC can declare what is standard - so ask them.

Standardization committees declare what is standard through the
standard document. There may be cases where the standard document is
unclear or contradictory, in which case clarification may be needed,
but the stack effect or COMPILE, is not one of these cases.

Ruvim

unread,
May 5, 2021, 2:08:33 PMMay 5
to
On 2021-05-05 17:37, Stephen Pelc wrote:
> On Wed, 05 May 2021 11:46:26 GMT, an...@mips.complang.tuwien.ac.at
> (Anton Ertl) wrote:
>
>> The standard stack effect of COMPILE, is ( xt -- ). If COMPILE,
>> behaves differently on your system, it's non-standard. I reported
>> this bug to you in 2015
>> <2015100907...@a4.complang.tuwien.ac.at>.
>
> NDCS = non default compilation semantics, e.g. IF
>
> And that's probably what triggered my NDCS esploration. The base
> problem comes from the standard's definitions of words. There are
> three cases:
> 1) normal words
> 2) immediate words
> 3) NDCS words

It's unclear do you mean the glossary entries, or the implementations in
particular Forth system?

In which group does the EXIT word fall?


The immediate words have non default compilation semantics. Probably you
wanted to place in the group 3 the NDCS words that are not implemented
as immediate words. And then the distribution of the words per these
three groups is system/implementation dependent. In some systems the
group 3 is empty.




> The standard only says how to handle cases 1) and 2).

You are right, the standard doesn't say how to perform compilation
semantics for NDCS words that are not immediate words.

The standard also doesn't say how to perform interpretation semantics
for the words with non default interpretation semantics.

It's the internal matters of a Forth system. And a Forth system even is
not obligated to use "COMPILE," or "EXECUTE" in its Forth text
interpreter at all.

But whatever matters a system does under the hood, it should not affect
the standard interfaces.


> So the answer to Ruvim's problem is "Don't do that".

This claim requires another ground.


> Until the standard encompasses NDCS words, the standard is incomplete.

Actually the standard does provide a mechanism to implement NDCS words —
it's the mechanism of immediacy — and this mechanism is capable to
implement any non default compilation semantics, and even default
compilation semantics in some exotic cases.

You also admit this in your "Special Words in Forth" paper, with
pointing to the problems in the popular implementations.

In the same time a system is allowed to use any other suitable mechanism
for that as well as the standard immediacy mechanism.



> The standard deliberately does not mandate implementation techniques
> and VFX uses a technique for NDCS words that is useful, but breaks
> careless tests.

Nothing internal implementation details can excuse a system in breaking
the specified interface of the "COMPILE," word.



> The EuroForth papers are there to read, and nobody has
> said that my analysis is wrong.

https://www.mpeforth.com/arena/SpecialWords3.pdf

It says that "COMPILE," may do optimization. It's correct.

Also it says that "COMPILE," can be used to perform compilation
semantics for the words like "IF", but then "COMPILE," will be broken:

| This technique can also be used for other words such as "IF",
| with the deliberate intention that the interpretation
| and compilation actions of a word can be separated.
| However, "COMPILE," is then broken as far as current standards
| are concerned because structure words such as "IF" produce
| or consume stack items, and string words parse the input stream.

It's also correct.

Even "IF" may be implemented as an ordinary word. The only requirement
is that the unspecified side effects of its compilation via "COMPILE,"
should be undetectable by a standard program. For example, a system can
use special internal stack for "orig". Or it can resolve "orig" in the
run-time.




> My conclusion from all this is that the standard has a bug in it.

Hope I can convince you that there mentioned issue is not a bug, but
something like misunderstanding.



> Unfortunately, fixing the bug will be a real pain.

A bug should be provable by an example.



--
Ruvim

dxforth

unread,
May 5, 2021, 9:49:52 PMMay 5
to
On 6/05/2021 00:37, Anton Ertl wrote:
> dxforth <dxf...@gmail.com> writes:
>>Only a TC can declare what is standard - so ask them.
>
> Standardization committees declare what is standard through the
> standard document. There may be cases where the standard document is
> unclear or contradictory, in which case clarification may be needed,
> but the stack effect or COMPILE, is not one of these cases.

The behaviour of test-if was ambiguous before it got to COMPILE, .
IMO once an ambiguous condition is in process, ANS has no say what
should happen.

Ruvim

unread,
May 6, 2021, 2:19:14 AMMay 6
to
On 2021-05-06 04:49, dxforth wrote:
> On 6/05/2021 00:37, Anton Ertl wrote:
>> dxforth <dxf...@gmail.com> writes:
>>> Only a TC can declare what is standard - so ask them.
>>
>> Standardization committees declare what is standard through the
>> standard document.  There may be cases where the standard document is
>> unclear or contradictory, in which case clarification may be needed,
>> but the stack effect or COMPILE, is not one of these cases.
>
> The behaviour of test-if was ambiguous before it got to COMPILE, .

Here it is:

: test-if
c" if" find dup 0= if ." unfound" 2drop exit then
1 = if ." executed" execute else ." compiled" compile, then
; immediate


In what place is it ambiguous? In "find"?



> IMO once an ambiguous condition is in process, ANS has no say what
> should happen.

Correct.

"The response of a Standard System to an ambiguous condition is left to
the discretion of the implementor" (A.2.1)


--
Ruvim

dxforth

unread,
May 6, 2021, 4:52:00 AMMay 6
to
On 6/05/2021 16:19, Ruvim wrote:
> On 2021-05-06 04:49, dxforth wrote:
>> On 6/05/2021 00:37, Anton Ertl wrote:
>>> dxforth <dxf...@gmail.com> writes:
>>>> Only a TC can declare what is standard - so ask them.
>>>
>>> Standardization committees declare what is standard through the
>>> standard document.  There may be cases where the standard document is
>>> unclear or contradictory, in which case clarification may be needed,
>>> but the stack effect or COMPILE, is not one of these cases.
>>
>> The behaviour of test-if was ambiguous before it got to COMPILE, .
>
> Here it is:
>
> : test-if
> c" if" find dup 0= if ." unfound" 2drop exit then
> 1 = if ." executed" execute else ." compiled" compile, then
> ; immediate
>
>
> In what place is it ambiguous? In "find"?

Using FIND to invoke IF is ambiguous. I've a good idea what will
happen on single-xt systems but that's all. Same for POSTPONE S" .
Dual-xt systems have muddied the waters. Today users have no way
to know what is portable - only what works on their system.

P Falth

unread,
May 6, 2021, 7:38:06 AMMay 6
to
On Thursday, 6 May 2021 at 10:52:00 UTC+2, dxforth wrote:
> On 6/05/2021 16:19, Ruvim wrote:
> > On 2021-05-06 04:49, dxforth wrote:
> >> On 6/05/2021 00:37, Anton Ertl wrote:
> >>> dxforth <dxf...@gmail.com> writes:
> >>>> Only a TC can declare what is standard - so ask them.
> >>>
> >>> Standardization committees declare what is standard through the
> >>> standard document. There may be cases where the standard document is
> >>> unclear or contradictory, in which case clarification may be needed,
> >>> but the stack effect or COMPILE, is not one of these cases.
> >>
> >> The behaviour of test-if was ambiguous before it got to COMPILE, .
> >
> > Here it is:
> >
> > : test-if
> > c" if" find dup 0= if ." unfound" 2drop exit then
> > 1 = if ." executed" execute else ." compiled" compile, then
> > ; immediate
> >
> >
> > In what place is it ambiguous? In "find"?
> Using FIND to invoke IF is ambiguous. I've a good idea what will
> happen on single-xt systems but that's all. Same for POSTPONE S" .
> Dual-xt systems have muddied the waters. Today users have no way
> to know what is portable - only what works on their system.

Yes I agree to this. My LXF is dual-xt. FIND on IF will return the interpretation
xt. When executed this will print an error message and abort.

In my opinion FIND was left in pre F94 state and not modified to align with
the execution, interpretation and compilation semantics definitions.

Of course you can get my IF to work with FIND by doing
: IF postpone IF ; immediate

As an alternative to FIND I can suggest
FIND-INTERPRET ( addr u -- addr u 0 | xt2 xt1 -1 )
FIND-COMPILE ( addr u -- addr u 0 | xt2 xt1 -1 )
FIND-POSTPONE ( addr u -- addr u 0 | xt2 xt1 -1 )

The result if found just needs to be executed to perform the respective actions
It also hides the implementation details ( single-xt, dual-xt, dual headers etc)

BR
Peter

Stephen Pelc

unread,
May 6, 2021, 9:46:18 AMMay 6
to
On Wed, 5 May 2021 21:08:28 +0300, Ruvim <ruvim...@gmail.com>
wrote:

>> NDCS = non default compilation semantics, e.g. IF
>>
>> And that's probably what triggered my NDCS esploration. The base
>> problem comes from the standard's definitions of words. There are
>> three cases:
>> 1) normal words
>> 2) immediate words
>> 3) NDCS words
>
>It's unclear do you mean the glossary entries, or the implementations in
>particular Forth system?
>
>In which group does the EXIT word fall?

Let's restate the groups:
a) normal words,
b) NDCS words,
c) Immediate words are a subset of NDCS words.

In most Forth systems, groups b) and c) are the same because the
system only has IMMEDIATE as a way to express NDCS behaviour.

In VFX, some special words are NDCS but not IMMEDIATE. The equivalent
of COMPILE, for such words is NDCS,

: ndcs, \ ??? xt -- ???
\ *G Perform the compilation action of an NDCS word. This may have
\ ** a stack effect or parse the input stream.

: compile-word \ i*x xt -- j*x
\ *G Process an XT for compilation. May parse or have stack effect.
dup ndcs? \ NDCS or normal
if ndcs, else compile, then
;

In VFX, most uses of COMPILE, should use COMPILE-WORD instead.
The alternative is to redefine COMPILE, to take note of NDCS words
but ... politics, politic, politics.

Ruvim

unread,
May 6, 2021, 10:07:26 AMMay 6
to
On 2021-05-06 14:38, P Falth wrote:
> On Thursday, 6 May 2021 at 10:52:00 UTC+2, dxforth wrote:
>> On 6/05/2021 16:19, Ruvim wrote:
>>> On 2021-05-06 04:49, dxforth wrote:
>>>> On 6/05/2021 00:37, Anton Ertl wrote:
>>>>> dxforth <dxf...@gmail.com> writes:
>>>>>> Only a TC can declare what is standard - so ask them.
>>>>>
>>>>> Standardization committees declare what is standard through the
>>>>> standard document. There may be cases where the standard document is
>>>>> unclear or contradictory, in which case clarification may be needed,
>>>>> but the stack effect or COMPILE, is not one of these cases.
>>>>
>>>> The behaviour of test-if was ambiguous before it got to COMPILE, .
>>>
>>> Here it is:
>>>
>>> : test-if
>>> c" if" find dup 0= if ." unfound" 2drop exit then
>>> 1 = if ." executed" execute else ." compiled" compile, then
>>> ; immediate
>>>
>>>
>>> In what place is it ambiguous? In "find"?
>> Using FIND to invoke IF is ambiguous. I've a good idea what will
>> happen on single-xt systems but that's all. Same for POSTPONE S" .
>> Dual-xt systems have muddied the waters. Today users have no way
>> to know what is portable - only what works on their system.
>
> Yes I agree to this. My LXF is dual-xt. FIND on IF will return the interpretation
> xt. When executed this will print an error message and abort.

It's OK for interpretation state, but not OK for compilation state.

In dual-xt systems FIND should depend on STATE and return the different
results depending on STATE for some words.

My clarification for FIND (the next version)
https://forth-standard.org/proposals/clarify-find-more-classic-approach?hideDiff#reply-682



>
> In my opinion FIND was left in pre F94 state and not modified to align with
> the execution, interpretation and compilation semantics definitions.

It's specification is too lean. But the Rationale part shows the
intention clearly. And using this rationale we can make the
specification better.



>
> Of course you can get my IF to work with FIND by doing
> : IF postpone IF ; immediate
>
> As an alternative to FIND I can suggest
> FIND-INTERPRET ( addr u -- addr u 0 | xt2 xt1 -1 )
> FIND-COMPILE ( addr u -- addr u 0 | xt2 xt1 -1 )
> FIND-POSTPONE ( addr u -- addr u 0 | xt2 xt1 -1 )

If you can implement this, nothing prevent you to implement STATE
dependent FIND

But what for do you need FIND-POSTPONE ?


> The result if found just needs to be executed to perform the respective actions
> It also hides the implementation details ( single-xt, dual-xt, dual headers etc)

It doesn't cover sing-xt systems. In these systems the corresponding
action should be performed only in the corresponding STATE.


--
Ruvim

Ruvim

unread,
May 6, 2021, 10:30:54 AMMay 6
to
On 2021-05-06 17:07, Ruvim wrote:
> On 2021-05-06 14:38, P Falth wrote:
[...]
>> As an alternative to FIND I can suggest
>> FIND-INTERPRET  ( addr u -- addr u 0 | xt2 xt1 -1 )
>> FIND-COMPILE     ( addr u -- addr u 0 | xt2 xt1 -1 )
>> FIND-POSTPONE  ( addr u -- addr u 0 | xt2 xt1 -1 )

They are quite close to FIND-NAME NAME>COMPILE

>
> If you can implement this, nothing prevent you to implement STATE
> dependent FIND

But only if for the cases FIND-INTEPRET and FIND-COMPILE, xt1 identify
either "EXECUTE" or "COMPILE," and nothing else.

Otherwise FIND cannot be implemented via these words.


>
> But what for do you need FIND-POSTPONE ?
>
>
>> The result if found just needs to be executed to perform the
>> respective actions
>> It also hides the implementation details ( single-xt, dual-xt, dual
>> headers etc)
>
> It doesn't cover sing-xt systems. In these systems the corresponding
> action should be performed only in the corresponding STATE.

I missed that they return two xt-s. Then yes, they cover single-xt
systems too.

But then what is a way to detect whether a word is an ordinary word?

And what is a way to get xt of an ordinary word, that identifies the
execution semantics for this word?


--
Ruvim

P Falth

unread,
May 6, 2021, 11:09:53 AMMay 6
to
The standard says that FIND may return different XTs depending on state.
It is not obliged to do so
I have seen your efforts.
In my opinion it is better to start with a clean sheet and implement something
that can substitute FIND and make it obsolete.

Peter

P Falth

unread,
May 6, 2021, 11:24:00 AMMay 6
to
On Thursday, 6 May 2021 at 16:30:54 UTC+2, Ruvim wrote:
> On 2021-05-06 17:07, Ruvim wrote:
> > On 2021-05-06 14:38, P Falth wrote:
> [...]
> >> As an alternative to FIND I can suggest
> >> FIND-INTERPRET ( addr u -- addr u 0 | xt2 xt1 -1 )
> >> FIND-COMPILE ( addr u -- addr u 0 | xt2 xt1 -1 )
> >> FIND-POSTPONE ( addr u -- addr u 0 | xt2 xt1 -1 )
> They are quite close to FIND-NAME NAME>COMPILE

Yes they are. But they also hide the NT and can thus accomodate
also a system with dual NTs. Someone (Mark Williams?) described
such a system that was simple and clean.

> > If you can implement this, nothing prevent you to implement STATE
> > dependent FIND
> But only if for the cases FIND-INTEPRET and FIND-COMPILE, xt1 identify
> either "EXECUTE" or "COMPILE," and nothing else.

To require that XT1 be limited to "EXECUTE" or "COMPILE," would severely
limit the possibilities of the system. Take for example a constant.
XT2 could be the actual value of the constant and XT1 LITERAL for compiling.

My LXF64 compiles to tokenized code. XT1 of interpret could there be a call
to a JIT compiler that compiles the tokens to native code and then executes it

> Otherwise FIND cannot be implemented via these words.

There is no requirements to implement FIND with these words.

> >
> > But what for do you need FIND-POSTPONE ?
> >
> >
> >> The result if found just needs to be executed to perform the
> >> respective actions
> >> It also hides the implementation details ( single-xt, dual-xt, dual
> >> headers etc)
> >
> > It doesn't cover sing-xt systems. In these systems the corresponding
> > action should be performed only in the corresponding STATE.
> I missed that they return two xt-s. Then yes, they cover single-xt
> systems too.
>
> But then what is a way to detect whether a word is an ordinary word?

That is not needed!

>
> And what is a way to get xt of an ordinary word, that identifies the
> execution semantics for this word?

' and ['] are still available for this.

BR
Peter
>
>
> --
> Ruvim

Anton Ertl

unread,
May 6, 2021, 1:00:50 PMMay 6
to
P Falth <peter....@gmail.com> writes:
>On Thursday, 6 May 2021 at 16:07:26 UTC+2, Ruvim wrote:
[...]
>The standard says that FIND may return different XTs depending on state.
>It is not obliged to do so

True. The intention behind that is probably that classic
single-xt+immediate-flag systems return the same xt in either state
and cmForth returns, for some words, one xt in one state, and a
different xt in the other state.

Sure, someone who implements a cmForth-like implementation could say
that there is no requirement in the specification to do it that way,
and produce a find that only returns one of the xts, but that would
mean that user-defined text interpreters that use FIND do not work on
that system.

Likewise for a more modern dual-xt system like yours.
Or another one:

https://forth-standard.org/proposals/clarify-find?hideDiff#reply-165

>I have seen your efforts.
>In my opinion it is better to start with a clean sheet and implement something
>that can substitute FIND and make it obsolete.

That has already been accepted:

https://forth-standard.org/proposals/find-name?hideDiff#reply-174

But FIND will continue to be in the standard for at least one more
release (or maybe more, it has not been declared obsolescent, and
nobody has proposed making it obsolescent, not even those who claim we
should not fix FIND, because it will be replaced).

Moreover, there are people who make an outrageous claims based on the
current specification of FIND (in particular, IIRC Stephen Pelc made
such a claim based on the usage of "immediate" in the current
specification that is at odds with the usage of "immediate" in the
rest of the document). So while FIND is still in the standard, it
will continue to be a sore point. That can be fixed by clarifying it.

Anton Ertl

unread,
May 6, 2021, 1:30:49 PMMay 6
to
P Falth <peter....@gmail.com> writes:
>To require that XT1 be limited to "EXECUTE" or "COMPILE," would severely
>limit the possibilities of the system. Take for example a constant.
>XT2 could be the actual value of the constant and XT1 LITERAL for compiling.

Yes, I also played with that idea. But it does not scale to doubles
and floats.

>My LXF64 compiles to tokenized code. XT1 of interpret could there be a call
>to a JIT compiler that compiles the tokens to native code and then executes it

If you implement EXECUTE, why go there?

Another idea I played with: for the compilation token xt1 xt2, let xt2
be a specialized compiler for xt1. I think you can find this idea in
my early writings about the compilation token. But we also have
COMPILE, and need to implement that. So the better way is to dispatch
the specialized compilers from "COMPILE,", and that's what we
implement now:

NAME>COMPILE always produces ' EXECUTE or ' COMPILE, as xt2. This
makes it straightforward to define FIND such that user-defined text
interpreters work. One can use SET-OPTIMIZER to tell the system what
COMPILE, should do for a certain word.

P Falth

unread,
May 6, 2021, 3:07:06 PMMay 6
to
On Thursday, 6 May 2021 at 19:30:49 UTC+2, Anton Ertl wrote:
> P Falth <peter....@gmail.com> writes:
> >To require that XT1 be limited to "EXECUTE" or "COMPILE," would severely
> >limit the possibilities of the system. Take for example a constant.
> >XT2 could be the actual value of the constant and XT1 LITERAL for compiling.
> Yes, I also played with that idea. But it does not scale to doubles
> and floats.

In fact my actual implementation is more compilated, XT2 is an address where
the constant, double or float is stored. XT1 is the appropriate fetch followed
by the appropriate literal

> >My LXF64 compiles to tokenized code. XT1 of interpret could there be a call
> >to a JIT compiler that compiles the tokens to native code and then executes it
> If you implement EXECUTE, why go there?

This is one area I have not decided yet. It could be that I will just execute
the tokenized code when interpreting. At least this would work well when the
tokenized code will be inlined while compiling. No need to waste space
compiling native code for it.

On the other hand words that for different reasons can not be inlined will need
to be compiled to native code so they later can be called directly from other
native code. In this case there is no need to keep the tokencode.

> Another idea I played with: for the compilation token xt1 xt2, let xt2
> be a specialized compiler for xt1. I think you can find this idea in
> my early writings about the compilation token. But we also have
> COMPILE, and need to implement that. So the better way is to dispatch
> the specialized compilers from "COMPILE,", and that's what we
> implement now:

My COMPILE, in both lxf and lxf64 are dumb. They will just compile a call
to the XT

> NAME>COMPILE always produces ' EXECUTE or ' COMPILE, as xt2. This
> makes it straightforward to define FIND such that user-defined text
> interpreters work. One can use SET-OPTIMIZER to tell the system what
> COMPILE, should do for a certain word.

None of my systems produces ' EXECUTE or ' COMPILE, as xt2.
I can see no requirement for limiting NAME>COMPILE in that way.

BR
Peter

Stephen Pelc

unread,
May 6, 2021, 3:28:12 PMMay 6
to
On Thu, 06 May 2021 16:26:01 GMT, an...@mips.complang.tuwien.ac.at
(Anton Ertl) wrote:

>Moreover, there are people who make an outrageous claims based on the
>current specification of FIND (in particular, IIRC Stephen Pelc made
>such a claim based on ...

I am proud to be thought to make outrageous claims, especially
when they are correct.

In particular, until we (standard committee and other interested
parties) come to terms with the impact of NDCS, arguing about
FIND and COMPILE, is just another silly discussion about how
many angels can dance on the head of a pin.

The easy thing to do is to declare non-immediate NDCS words
as non-compliant. Alternatively, you open the box and enable
new standards-compliant notations such as interpretive
BEGIN ... UNTIL and DO ... LOOP.

You have to start by understanding that the standards from
ANS-94 onwards have bugs. This is not to put the authors down,
but to realise that we are all imperfect.

Ruvim

unread,
May 7, 2021, 7:12:28 AMMay 7
to
Taking into account that "ndcs," just performs another xt:

: (ndcs,) \ i*x xt -- j*x
>code-len @ execute \ execute NDCS/IMMEDIATE word
;

Why not return this xt by "find" ?


: find ( c-addr -- c-addr 0 | xt -1 | xt 1 )
find dup 0= if exit then drop ( xt1 )
dup ndcs? if >code-len @ 1 else
dup immediate? if 1 else -1 then then ( xt1 xt2 n )
state @ if rot else swap then drop
;


After this fix all my tests work as expected.

To be on the safe side, I would redefine/fix some other words too, to
exclude situations when "compile," produces unexpected stack effect when
it's applied to some xt.

Nothing standard word should return such xt for which "compile,"
produces unexpected stack effect.



--
Ruvim

Ruvim

unread,
May 7, 2021, 9:11:34 AMMay 7