Problem: LEAVE and UNLOOP are defined to have no interpretation
semantics, but an execution semantics. This implies that ['] LEAVE
EXECUTE is equivalent to LEAVE within a loop body. I checked Gforth,
bigForth, and VFX, and this is not the case in any of these systems.
: test 0 ?DO i dup . 3 = IF ['] leave execute THEN LOOP ;
VFX fails during execution with a meaningful error message:
10 test 0 1 2 3
Err# -14 ERR: Attempt to interpret a compile only definition.
Gforth fails while compiling with a meaningful error message:
:1: Cannot tick compile-only word (try COMP' ... DROP)
: test 0 ?DO i dup . 3 = IF ['] >>>leave<<< execute THEN LOOP ;
bigForth fails silently without a meaningful error message:
10 test 0 1 2 3 4 5 6 7 8 9 ok
Feel free to check more. UNLOOP is defined similarly, and while Gforth
and VFX perform ['] UNLOOP EXECUTE correctly, bigForth doesn't (and it
would not be difficult to "fix" bigForth). However, I consider the
standard to be overspecified here, too. There is no practical reason
why UNLOOP must have execution semantics.
Solution: Remove "Execution:" from the definition of LEAVE and UNLOOP.
Insert instead
Compilation: ( -- )
Append the run-time semantics given below to the current
definition.
Run-Time:
Rationale:
This change is to allow alternative implementations of LEAVE and UNLOOP
with special compilation semantics. Especially for LEAVE, this is
common practice.
--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/
|
|
0
|
|
|
|
Reply
|
bernd.paysan (2408)
|
5/9/2012 5:42:13 PM |
|
Bernd Paysan <bernd.paysan@gmx.de> writes Re: [forth200x] RfD: Drop execution semantics of LEAVE and UNLOOP
[..]
> Problem: LEAVE and UNLOOP are defined to have no interpretation
> semantics, but an execution semantics. This implies that ['] LEAVE
> EXECUTE is equivalent to LEAVE within a loop body. I checked Gforth,
> bigForth, and VFX, and this is not the case in any of these systems.
[..]
> bigForth fails silently without a meaningful error message:
> 10 test 0 1 2 3 4 5 6 7 8 9 ok
> Feel free to check more. UNLOOP is defined similarly, and while Gforth
> and VFX perform ['] UNLOOP EXECUTE correctly, bigForth doesn't
iForth version 4.0.807, generated 21:33:31, February 22, 2012.
x86_64 binary, native floating-point, extended precision.
Copyright 1996 - 2012 Marcel Hendrix.
FORTH> : test 0 ?DO i dup . 3 = IF ['] leave execute THEN LOOP ; ok
FORTH> 10 test 0 1 2 3
Error -26
No LOOP defined ?
FORTH> : test2 0 ?DO i dup . 3 = IF ['] unloop execute THEN LOOP ; ok
FORTH> 10 test2 0 1 2 3
Error -26
No LOOP defined ?
Strange messages perhaps, but perfectly obvious from the compiler's
viewpoint.
-marcel
|
|
0
|
|
|
|
Reply
|
mhx (2133)
|
5/9/2012 6:15:29 PM
|
|
"Bernd Paysan" <bernd.paysan@gmx.de> wrote in message
news:joea9l$vge$1@online.de...
> Problem: LEAVE and UNLOOP are defined to have no interpretation
> semantics, but an execution semantics. This implies that ['] LEAVE
> EXECUTE is equivalent to LEAVE within a loop body. I checked Gforth,
> bigForth, and VFX, and this is not the case in any of these systems.
>
> : test 0 ?DO i dup . 3 = IF ['] leave execute THEN LOOP ;
>
> VFX fails during execution with a meaningful error message:
> 10 test 0 1 2 3
> Err# -14 ERR: Attempt to interpret a compile only definition.
>
> Gforth fails while compiling with a meaningful error message:
> :1: Cannot tick compile-only word (try COMP' ... DROP)
> : test 0 ?DO i dup . 3 = IF ['] >>>leave<<< execute THEN LOOP ;
>
> bigForth fails silently without a meaningful error message:
> 10 test 0 1 2 3 4 5 6 7 8 9 ok
>
> Feel free to check more.
Win32Forth
10 TEST 0 1 2 3 ok
BB4WForth
10 TEST
0 1 2 3 ok
RP
|
|
0
|
|
|
|
Reply
|
do_not_have8204 (63)
|
5/10/2012 8:10:52 AM
|
|
On May 10, 12:47=A0am, Krishna Myneni <krishna.myn...@ccreweb.org>
wrote:
I hasten to say that 4tH still uses a control stack with reference (as
in Forth-79). It's pretty bullet proof as long as you treat it as a
stack, even when resolving complex loops like BEGIN..
WHILE..WHILE..UNTIL. Even DO..LOOP works pretty well, unless you're
trying to resolve a LEAVE. That's why my LEAVE is still Forth-79, that
is: it sets the counter to the limit, job done. UNLOOP is inlined,
"2R> 2DROP". Both cannot be ticked, so this discussion doesn't really
touch me.
I've never been a proponent of all "fixes" concerning DO..LOOP and
your results just confirm this point of view. The idea of somehow
"resolving" LEAVE is flawed at best, because it can be embedded in an
IF..THEN statement (which needs to be resolved first). I found the
same problems when trying to develop my DONE..DONE statement, which
executes when a while has failed. I could not make a BREAK or CONTINUE
easily for that very same reason.
But why are we continuing to try to "fix" something that is so
profoundly flawed? Why can't we make the right decision and fix it
once and for all?
10 0 2 +DO .. LOOP
which compiles to:
swap
>r >r >r
:1 2 rpick rover -
0=3D if branch :2
..
rover r+
branch :1
2: ...
(Probably some assembly required, but you catch my drift). Where ?DO
equals 1 +DO.
Hans Bezemer
|
|
0
|
|
|
|
Reply
|
the.beez.speaks (110)
|
5/14/2012 7:14:08 AM
|
|
> This change is to allow alternative implementations of LEAVE and UNLOOP
> with special compilation semantics. Especially for LEAVE, this is
> common practice.
It's very interesting most Forths assume compilation semantics such that your ANS compliant example breaks them. Perhaps it would be better to close this loophole by declaring LEAVE's immediacy. Then you could do things like
: ?DONE POSTPONE IF POSTPONE LEAVE POSTPONE THEN
; IMMEDIATE
: FOO 0 DO I 3 = ?DONE LOOP ;
There are no signs in DPANS saying "There Be Dragons", so it's also possible to do something like this:
: FOO DUP 1+ >R . ['] R> EXECUTE . ; ok
4 FOO 4 ACCESS_VIOLATION ( SwiftForth )
Whenever I see "Interpretation semantics for this word are undefined" in the DPANS standard, I assume the word is IMMEDIATE and "compile-only". Why don't we just call a spade a spade and declare that this is the case?
-Brad
|
|
0
|
|
|
|
Reply
|
hwfwguy (347)
|
5/22/2012 4:54:51 PM
|
|
On 5/22/12 6:54 AM, hwfwguy@gmail.com wrote:
>> This change is to allow alternative implementations of LEAVE and UNLOOP
>> with special compilation semantics. Especially for LEAVE, this is
>> common practice.
>
> It's very interesting most Forths assume compilation semantics such that your ANS compliant example breaks them. Perhaps it would be better to close this loophole by declaring LEAVE's immediacy. Then you could do things like
>
> : ?DONE POSTPONE IF POSTPONE LEAVE POSTPONE THEN
> ; IMMEDIATE
>
> : FOO 0 DO I 3 = ?DONE LOOP ;
>
> There are no signs in DPANS saying "There Be Dragons", so it's also possible to do something like this:
>
> : FOO DUP 1+>R . ['] R> EXECUTE . ; ok
> 4 FOO 4 ACCESS_VIOLATION ( SwiftForth )
>
> Whenever I see "Interpretation semantics for this word are undefined" in the DPANS standard, I assume
> the word is IMMEDIATE and "compile-only". Why don't we just call a spade a spade and declare that this is the case?
That's a good working assumption. However, to state that a word is
"compile-only" basically *forbids* any other implementation. We know of
implementations in which DO, LOOP, etc., can be used interpretively
(Open Firmware is one example). That is not illegal. However, writers of
applications are warned by the "undefined" language that they cannot
*depend* on such a feature.
"Undefined" means exactly that: implementations are permitted to support
the behavior, issue an error message, erase your hard drive, post an
insulting status on Facebook, or anything else, and a user who tries to
test the limits of the behavior in question are warned that there is no
consistent or portable semantics there.
Cheers,
Elizabeth
--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com
"Forth-based products and Services for real-time
applications since 1973."
==================================================
|
|
0
|
|
|
|
Reply
|
erather (2080)
|
5/22/2012 5:33:14 PM
|
|
On Tue, 22 May 2012 09:54:51 -0700 (PDT), hwfwguy@gmail.com wrote:
>> This change is to allow alternative implementations of LEAVE and UNLOOP
>> with special compilation semantics. Especially for LEAVE, this is
>> common practice.
>
>It's very interesting most Forths assume compilation semantics such that
>your ANS compliant example breaks them. Perhaps it would be better to close
>this loophole by declaring LEAVE's immediacy.
The problem is then that immediacy implies that the compilation
semantics (behaviour) are the same as the interpretation
behaviour. It is better that words with undefined interpretation
semantics only have a specified run-time.
>Whenever I see "Interpretation semantics for this word are undefined"
>in the DPANS standard, I assume the word is IMMEDIATE and "compile-only".
>Why don't we just call a spade a spade and declare that this is the case?
Because it isn't necessary. Most of the words in VFX Forth that are
IMMEDIATE are only IMMEDIATE because the standard says they have to
be.
Note that I am only talking about desktopsystems here. In standalone
embedded systems immediacy is still a useful attribute.
Stephen
--
Stephen Pelc, stephenXXX@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads
|
|
0
|
|
|
|
Reply
|
stephenXXX (1297)
|
5/22/2012 6:52:20 PM
|
|
On May 9, 1:42=A0pm, Bernd Paysan <bernd.pay...@gmx.de> wrote:
> Problem: LEAVE and UNLOOP are defined to have no interpretation
> semantics, but an execution semantics. =A0This implies that ['] LEAVE
> EXECUTE is equivalent to LEAVE within a loop body.
I do not believe that this premise is valid.
(1) ['] clearly specifies that it gives the same result as ' does when
interpreting.
(2) ' clearly specifies that *when interpreting*
' foo EXECUTE
.... is the same as interpreting "foo".
(3) Thus ['] foo EXECUTE while compiling should give the
interpretation semantics of a word.
(4) LEAVE and UNLOOP are specified to have undefined interpreter
semantics, and so ['] LEAVE EXECUTE which while compiling is *not*
required to be equivalent to LEAVE within a loop body.
*However* my view is that there is still merit to one part of this
proposal. This is based on a point regarding which there is no
consensus, and upon which I appear to differ for Bernd, who has
suggested in another forum that this may be because his perspective is
too abstract for my humble mental capacities. And that may very well
be the case, so if I am wrong on this point, I'll need the assistance
of a somewhat less than lofty explanation why.
This goes to the heart of the notion of what "execution semantics" are
and what it implies for a word to be specified with special
compilation semantics. I have always had a tendency to view the first
clause in the specification of the term "execution" as the primary
clause. This clause is highlighted in the quote of relevant section
with * marks:
"3.4.3.1 Execution semantics"
"The execution semantics of each Forth definition are specified in
an Execution: section of its glossary entry. When a definition has
only one specified behavior, the label is omitted."
"*Execution may occur implicitly, when the definition into which it
has been compiled is executed*, or explicitly, when its execution
token is passed to EXECUTE. The execution semantics of a syntactically
correct definition under conditions other than those specified in this
Standard are implementation dependent."
"Glossary entries for defining words include the execution
semantics for the new definition in a name Execution: section."
What is not mentioned in the first paragraph of the specification is
that not all definitions have an "Execution:" section.
In my view, the special cases are implied by the highlighted section:
"Execution may occur implicitly, when the definition into which it has
been compiled is executed."
In most cases, the execution semantics are atomic. They occur at
execution time of the word into which the execution semantics have
been compiled, and all that is required to get that is for the system
to be in compilation state when encountering the word in the source.
However, in some cases, the execution semantics are not atomic. [CHAR]
must parse the following token at compile time to obtain the
character, which is placed on the stack at execution time, so correct
execution is contingent on both a compile-time and a run-time action.
THEN must find a valid orig on the compilation structures stack at
compile time, in order to be the position at which execution resumes
following, eg, the run-time of IF consuming a zero.
In scanning through the Standard, every instance where there is no
"Execution:" section, the situation involves this kind of non-atomic
execution semantics.
While the UNLOOP semantics are atomic, and properly specified, the
LEAVE semantics are not *necessarily* atomic, *unless* one provides an
implementation such as pushing the target leave address onto the
return stack. If one implements LEAVE as an unconditional branch,
tracking the LEAVE origins in some way outside of the compilation
structures stack, then the semantics are not in fact atomic.
This may have been overlooked because the former was the most common
LEAVE implementation in the early 90's, or because the record keeping
for the branch version of LEAVE is explicitly somewhere other than the
compilation structures stack, but in any event, LEAVE is, in my view,
properly defined as having special compilation semantics, as the other
structure words are.
I view UNLOOP as having atomic execution semantics similar to RDROP
and EXIT, and so I do not support the proposal with respect to UNLOOP.
> Solution: Remove "Execution:" from the definition of LEAVE.
> Insert instead
> Compilation: ( -- )
> =A0 =A0 =A0 =A0 Append the run-time semantics given below to the current
> =A0 =A0 =A0 =A0 =A0definition.
>
> Run-Time:
> Rationale:
> This change is to allow alternative implementations of LEAVE with special
> compilation semantics. =A0This is common practice.
|
|
0
|
|
|
|
Reply
|
agila61 (3956)
|
5/22/2012 10:38:03 PM
|
|
BruceMcF wrote:
> "*Execution may occur implicitly, when the definition into which it
> has been compiled is executed*, or explicitly, when its execution
> token is passed to EXECUTE. The execution semantics of a syntactically
> correct definition under conditions other than those specified in this
> Standard are implementation dependent."
>
> "Glossary entries for defining words include the execution
> semantics for the new definition in a name Execution: section."
>
> What is not mentioned in the first paragraph of the specification is
> that not all definitions have an "Execution:" section.
>
> In my view, the special cases are implied by the highlighted section:
> "Execution may occur implicitly, when the definition into which it has
> been compiled is executed."
Yes, but that is added run-time code. There is an OR in the statement
above, and I imply that execution semantics has both caracteristics:
Either where it has been comiled to, *or* when it is executed. The
declaration of an execution semantics also implies that there is an xt,
which can be appended to the current definition using COMPILE,. This is
often not the case with LEAVE, but typically works with UNLOOP.
> In most cases, the execution semantics are atomic. They occur at
> execution time of the word into which the execution semantics have
> been compiled, and all that is required to get that is for the system
> to be in compilation state when encountering the word in the source.
>
> However, in some cases, the execution semantics are not atomic. [CHAR]
> must parse the following token at compile time to obtain the
> character, which is placed on the stack at execution time, so correct
> execution is contingent on both a compile-time and a run-time action.
But that is not execution semantics. That's compile-time and run-time
semantics. [CHAR] is usually implemented as immediate word, and its
execution semantics therefore are equal to its compilation semantics.
The run-time semantics from [CHAR] is equal to that of POSTPONE LITERAL.
> THEN must find a valid orig on the compilation structures stack at
> compile time, in order to be the position at which execution resumes
> following, eg, the run-time of IF consuming a zero.
>
> In scanning through the Standard, every instance where there is no
> "Execution:" section, the situation involves this kind of non-atomic
> execution semantics.
>
> While the UNLOOP semantics are atomic, and properly specified, the
> LEAVE semantics are not *necessarily* atomic, *unless* one provides an
> implementation such as pushing the target leave address onto the
> return stack. If one implements LEAVE as an unconditional branch,
> tracking the LEAVE origins in some way outside of the compilation
> structures stack, then the semantics are not in fact atomic.
>
> This may have been overlooked because the former was the most common
> LEAVE implementation in the early 90's, or because the record keeping
> for the branch version of LEAVE is explicitly somewhere other than the
> compilation structures stack, but in any event, LEAVE is, in my view,
> properly defined as having special compilation semantics, as the other
> structure words are.
>
> I view UNLOOP as having atomic execution semantics similar to RDROP
> and EXIT, and so I do not support the proposal with respect to UNLOOP.
Hm, ok. But e.g. EXIT does not have atomic execution semantics in
Gforth. It corrects the locals stack (if there is anything to correct,
i.e. if the word has locals), and then compiles ;S, the return
primitive.
--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/
|
|
0
|
|
|
|
Reply
|
bernd.paysan (2408)
|
5/29/2012 4:50:37 PM
|
|
On May 29, 12:50=A0pm, Bernd Paysan <bernd.pay...@gmx.de> wrote:
> BruceMcF wrote:
> > =A0 =A0"*Execution may occur implicitly, when the definition into which=
it
> > has been compiled is executed*, or explicitly, when its execution
> > token is passed to EXECUTE. The execution semantics of a syntactically
> > correct definition under conditions other than those specified in this
> > Standard are implementation dependent."
> > =A0 =A0"Glossary entries for defining words include the execution
> > semantics for the new definition in a name Execution: section."
> > What is not mentioned in the first paragraph of the specification is
> > that not all definitions have an "Execution:" section.
> > In my view, the special cases are implied by the highlighted section:
> > "Execution may occur implicitly, when the definition into which it has
> > been compiled is executed."
> Yes, but that is added run-time code.
Yes, when converted from the standard specification of behavior into
implementation, it implies added run-time code.
It does not, however, imply "nothing but adding run-time code", since
"into which is has been compiled" is not *restricted to* merely
appending execution semantics. That is the *default* compilation
semantics, but "compilation" in *general* terms applies to all the
*different* compilation behaviors within the scope of the standard.
|
|
0
|
|
|
|
Reply
|
agila61 (3956)
|
5/29/2012 5:38:52 PM
|
|
BruceMcF wrote:
>> > In my view, the special cases are implied by the highlighted
>> > section: "Execution may occur implicitly, when the definition into
>> > which it has been compiled is executed."
>
>> Yes, but that is added run-time code.
>
> Yes, when converted from the standard specification of behavior into
> implementation, it implies added run-time code.
>
> It does not, however, imply "nothing but adding run-time code", since
> "into which is has been compiled" is not *restricted to* merely
> appending execution semantics. That is the *default* compilation
> semantics, but "compilation" in *general* terms applies to all the
> *different* compilation behaviors within the scope of the standard.
Ok, let's go back to the assumption:
If it has execution semantics, it has an xt.
An xt can be COMPILE,d to generate code. This is "appending run-time
code".
In a traditional system, there is little choice what COMPILE, can do -
it is usually equivalent to , or similar. If you want compilation
semantics code to be executed at compile-time, you use the IMMEDIATE
flag. So in a mostly traditional implementation, going through
"execution semantics" IMHO is too strict.
In a smart-COMPILE, system like VFX, COMPILE, can do all kind of things
at compile time. Going through "execution semantics" might be
appropriate, but does not adequately describe what happens.
--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/
|
|
0
|
|
|
|
Reply
|
bernd.paysan (2408)
|
5/30/2012 5:41:47 PM
|
|
On May 30, 1:41=A0pm, Bernd Paysan <bernd.pay...@gmx.de> wrote:
> Ok, let's go back to the assumption:
> If it has execution semantics, it has an xt.
If it has discrete execution semantics, there should be an xt for
those. Anf from the specification of ' and ['] if it has defined
interpretation semantics that are distinct from the discrete execution
semantics, there should be an xt for those as well.
> An xt can be COMPILE,d to generate code. =A0This is "appending run-time
> code".
But appending run-time code is about the implementation. Appending run-
time behavior is what the specification says.
> In a traditional system, there is little choice what COMPILE, can do -
> it is usually equivalent to , or similar. =A0If you want compilation
> semantics code to be executed at compile-time, you use the IMMEDIATE
> flag. =A0So in a mostly traditional implementation, going through
> "execution semantics" IMHO is too strict.
In a mostly traditional implementation, the xt returned with the
IMMEDIATE flag still serves to *identify* the execution semantics,
which are provided for in part at compile-time and in part at run-
time.
|
|
0
|
|
|
|
Reply
|
agila61 (3956)
|
5/30/2012 10:33:42 PM
|
|
|
11 Replies
46 Views
(page loaded in 0.139 seconds)
|