|
|||
|
Does ?DO force DO 's definition to become bloated? Because both DO and ?DO must work with LOOP and +LOOP, DO ballooned to a 13 word definition. That's two more than ?DO ... DO went from a simple 4 word definition to a bunch of do-nothing code. This is because DO must mirror ?DO's functionality and ?DO must work with LOOP and +LOOP . Does this sound correct to you? Also, is it possible to define ?DO in terms of DO ? I assuming that's a "no", since DO must mirror ?DO 's functionality. Part of ?DO 's and now DO 's size was because I needed to expand the definition of IF inline for them to work... I'll have to track down that issue. I tried to use IF directly. I have COMPILE and [COMPILE] which work and will give them a try to see what is closest or working. I also have COMPILE, now and POSTPONE too but I'm avoiding their use in my base code. COMPILE and [COMPILE] and , (comma) make sense to me for now. Also, POSTPONE needs some thorough testing ... I thought it should've worked in the same places as COMPILE and [COMPILE] . I based POSTPONE off of one of two common definitions posted to c.l.f. years ago. Rod Pemberton |
|
|
||||
|
||||
|
|
|
|||
|
On 3/30/12 12:40 PM, Rod Pemberton wrote:
> Does ?DO force DO 's definition to become bloated? > > Because both DO and ?DO must work with LOOP and +LOOP, DO ballooned > to a 13 word definition. That's two more than ?DO ... > > DO went from a simple 4 word definition to a bunch of do-nothing code. This > is because DO must mirror ?DO's functionality and ?DO must work with LOOP > and +LOOP . Does this sound correct to you? > > Also, is it possible to define ?DO in terms of DO ? I assuming that's a > "no", since DO must mirror ?DO 's functionality. > > Part of ?DO 's and now DO 's size was because I needed to expand the > definition of IF inline for them to work... I'll have to track down that > issue. I tried to use IF directly. I have COMPILE and [COMPILE] which work > and will give them a try to see what is closest or working. I also have > COMPILE, now and POSTPONE too but I'm avoiding their use in my base code. > COMPILE and [COMPILE] and , (comma) make sense to me for now. Also, > POSTPONE needs some thorough testing ... I thought it should've worked in > the same places as COMPILE and [COMPILE] . I based POSTPONE off of > one of two common definitions posted to c.l.f. years ago. The function of ?DO is simply to determine whether to proceed with DO or not. So there's no need to incorporate DO's logic in ?DO or vice-versa. Just compile ?DO followed by the runtime of DO, and all that will be skipped if ?DO's test fires. 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." ================================================== |
|
|||
|
Rod Pemberton wrote: <jl5cp3$tev$1@speranza.aioe.org>
> Does ?DO force DO 's definition to become bloated? It shouldn't change DO at all. ?DO should basically compile `2DUP <> IF DO`, and the IF's compile-time info should be stored so that it will be resolved as if it were a LEAVE. Do you have LEAVE yet? I'd implement that before ?DO. --Josh |
|
|||
|
On 3/30/12 1:46 PM, Josh Grams wrote:
> Rod Pemberton wrote:<jl5cp3$tev$1@speranza.aioe.org> >> Does ?DO force DO 's definition to become bloated? > > It shouldn't change DO at all. > > ?DO should basically compile `2DUP<> IF DO`, and the IF's compile-time > info should be stored so that it will be resolved as if it were a LEAVE. Alternatively, the compile-time ?DO can compile a reference to the runtime ?DO which checks the stack arguments and, if necessary, discard the loop parameters and branch to the address beyond the next LOOP or +LOOP. Then compile a reference to the normal runtime for DO, which will be part of what gets skipped if necessary. In other words, keep these words suitably factored. Neither has to do the other's job. For example: : DO ( -- flag addr) POSTPONE (DO) 0 (BEGIN) ; IMMEDIATE : ?DO ( -- addr1 flag addr2) POSTPONE (?DO) (BEGIN) POSTPONE (DO) 1 (BEGIN) ; IMMEDIATE ....where (DO) and (?DO) are the run-time actions. (?DO) contains a forward branch which compile-time LOOP or +LOOP must resolve. (BEGIN) leaves on the compile-time stack an address for LOOP or +LOOP to branch back to, and a flag. 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." ================================================== |
|
|||
|
"Josh Grams" <josh@qualdan.com> wrote in message
news:4f7645ed$0$23410$882e7ee2@usenet-news.net... > Rod Pemberton wrote: <jl5cp3$tev$1@speranza.aioe.org> > > Does ?DO force DO 's definition to become bloated? > > It shouldn't change DO at all. .... > ?DO should basically compile `2DUP <> IF DO`, ?DO first compiles (?DO) which is currently `2DUP <>` in my case. That's followed by the definition of IF inlined into ?DO . I've yet to find out why IF itself won't work there. I thought it was an issue with needing COMPILE or [COMPILE] but maybe IF just needed to be in (?DO) ... Continuing, that's followed by compiling (DO) which is what DO compiles. Finally, there is a HERE at the end of ?DO . The HERE is definately different from what you mentioned. Otherwise, it's probably equivalent. So, when using ?DO there are two HERE addresses on the stack, one due to the IF and one by the explict HERE. One address is for looping and the other is for the conditional branch in ?DO . That means that LOOP and +LOOP are always getting two addresses from ?DO . So, they must be coded to use both of them. That means that DO must also supply two addresses, not just one. Yes? If only one is provided by DO , then a stack underflow will occur. I.e., that implies that DO 's code must mirror the implementation of ?DO in terms of placing addresses on the stack. If LOOP and +LOOP didn't have to backfill in the conditional forward address from ?DO , then DO would be simpler. (Just prior to me posting this, Ms. Rather posted a solution which doesn't require both DO and ?DO putting two addresses onto the stack.) > [...] and the IF's compile-time info should be stored so > that it will be resolved as if it were a LEAVE. > Are you talking about the linked-list created "leave" and "rake" chaining implementation of LEAVES? > Do you have LEAVE yet? No. > I'd implement that before ?DO. Why? ISTM that the "leaves-rake" method is complicated. ISTM also that it doesn't fit well with the other control-flow words. From what I can tell, it seems that ANS LEAVE also requires a forward reference branch address that must be resolved, like ?DO . I'm not sure yet how to work that into DO ?DO LOOP +LOOP yet. AIUI, the old fig-Forth LEAVE didn't immediately exit the loop. It just changed the parameters so the loop exited. Having to implement a LEAVE which immediately exits the loop is making me hesistant. Rod Pemberton |
|
|||
|
"Elizabeth D. Rather" <erather@forth.com> wrote in message
news:sr6dnQSBkK-NNuvSnZ2dnUVZ_vednZ2d@supernews.com... > On 3/30/12 1:46 PM, Josh Grams wrote: > > Rod Pemberton wrote:<jl5cp3$tev$1@speranza.aioe.org> > >> Does ?DO force DO 's definition to become bloated? > > > > It shouldn't change DO at all. > > > > ?DO should basically compile `2DUP<> IF DO`, and the IF's compile-time > > info should be stored so that it will be resolved as if it were a LEAVE. > > Alternatively, the compile-time ?DO can compile a reference to the > runtime ?DO which checks the stack arguments and, if necessary, discard > the loop parameters and branch to the address beyond the next LOOP or > +LOOP. Then compile a reference to the normal runtime for DO, which will > be part of what gets skipped if necessary. > > In other words, keep these words suitably factored. Neither has to do > the other's job. > > For example: > > : DO ( -- flag addr) > POSTPONE (DO) 0 (BEGIN) ; IMMEDIATE > > : ?DO ( -- addr1 flag addr2) > POSTPONE (?DO) (BEGIN) > POSTPONE (DO) 1 (BEGIN) ; IMMEDIATE > > ...where (DO) and (?DO) are the run-time actions. (?DO) contains a > forward branch which compile-time LOOP or +LOOP must resolve. (BEGIN) > leaves on the compile-time stack an address for LOOP or +LOOP to branch > back to, and a flag. > Ok, make LOOP and +LOOP "smarter" or DO/?DO-aware ... I had decided against attempting to pair them, in case there was some unforeseen issue leading to a mismatch. But, that works or should. It's simple enough. My ?DO is putting two addresses onto the stack, one for the loop and one for the forward branch that needs resolving. Because of ?DO needing two addresses and it "passing" both to LOOP and +LOOP , I changed DO to also put two addresses onto the stack instead of only one. That's what I meant by the bloating. Rod Pemberton |
|
|||
|
Rod Pemberton wrote: <jl6bon$mnj$1@speranza.aioe.org>
> "Josh Grams" <josh@qualdan.com> wrote in message > news:4f7645ed$0$23410$882e7ee2@usenet-news.net... > > (Just prior to me posting this, Ms. Rather posted a solution which doesn't > require both DO and ?DO putting two addresses onto the stack.) > >> [...] and the IF's compile-time info should be stored so >> that it will be resolved as if it were a LEAVE. > > Are you talking about the linked-list created "leave" and "rake" chaining > implementation of LEAVES? It doesn't have to be a linked-list implementation -- you can keep the forward branch references on the stack along with a count. It would be like the code that Elizabeth posted, but instead of a flag and a single address, you would have a count on top of 0 or more addresses. E.g. assuming (DO) is 2>R and (?DO) is 2DUP <>: : do ( C: -- 0 dest ) postpone (do) 0 postpone begin ; immediate : ?DO ( C: -- orig 1 dest ) postpone (?do) postpone if 1 postpone (do) postpone begin ; immediate : leave ( u*orig u dest -- u+1*orig u+1 dest ) postpone unloop >r >r postpone ahead r> 1+ r> ; immediate At the end of loop/+loop you want to resolve all the branches: : thens ( u*orig u -- ) begin dup while 1- over postpone then repeat drop ; Does that make sense? --Josh |
|
|||
|
On Mar 31, 11:58*am, Josh Grams <j...@qualdan.com> wrote:
> It doesn't have to be a linked-list implementation -- you can keep the > forward branch references on the stack along with a count. LEAVE does not have special compilation semantics, in particular it does not have access to a do-sys, so this can not be a conforming implementation. Segher |
|
|||
|
Rod Pemberton wrote:
> AIUI, the old fig-Forth LEAVE didn't immediately exit > the loop. It just changed the parameters so the loop exited. Having to > implement a LEAVE which immediately exits the loop is making me hesistant. I agree with you. With the danger of starting a flame war again, I kept with the original Forth-79 implementation. First, now with ?DO we have TWO words which make the decision to branch or not. Second, the redefinition of Forth-83 to allow to "drop" through the loop instead of doing the sensible thing and abort (yeah, you can now cover the entire address range, cool) made an already somewhat flawed construction worse. So, ?DO was added to make it still worse. Now we have a very, very flawed LOOP construct, which is beyond repair. Yes, beyond repair, because it would break so much code to fix this, nobody would never, ever touch this one. Hans Bezemer |
|
|||
|
On Mar 31, 5:58*am, Josh Grams <j...@qualdan.com> wrote:
> : leave ( u*orig u dest -- u+1*orig u+1 dest ) > * * * * postpone unloop > * * * * >r *>r postpone ahead r> 1+ *r> ; immediate That's broken, since there can be arbitrary structured words the DO ... LOOP. If the compile structures stack is the data stack and you have a data stack index, which I think Rod will have, you can hold a leave count in one variable and the height of the data stack in another. When you do LEAVE, increment the leave count, and bubble the orig down to the original DO-LOOP stack height. Then RAKE-LEAVES just postpones a THEN for each orig, which should be on the top of the stack, until the leave count is 0. Then DO would save the old leave count and data stack height on the return stack and LOOP and +LOOP would restore it. |
|
|||
|
On Mar 31, 3:29*am, "Rod Pemberton" <do_not_h...@noavailemail.cmm>
wrote: > "Josh Grams" <j...@qualdan.com> wrote in message > > news:4f7645ed$0$23410$882e7ee2@usenet-news.net...> Rod Pemberton wrote: <jl5cp3$te...@speranza.aioe.org> > > > Does ?DO force DO 's definition to become bloated? > > > It shouldn't change DO at all. > > ... > > > ?DO should basically compile `2DUP <> IF DO`, > > ?DO first compiles (?DO) which is currently `2DUP <>` in my case. *That's > followed by the definition of IF inlined into ?DO . *I've yet to find out > why IF itself won't work there. *I thought it was an issue with needing > COMPILE or [COMPILE] but maybe IF just needed to be in (?DO) ... > Continuing, that's followed by compiling (DO) which is what DO compiles. > Finally, there is a HERE at the end of ?DO . *The HERE is definately > different from what you mentioned. *Otherwise, it's probably equivalent.. > > So, when using ?DO there are two HERE addresses on the stack, one due to the > IF and one by the explict HERE. *One address is for looping and the other is > for the conditional branch in ?DO . *That means that LOOP and +LOOP are > always getting two addresses from ?DO . *So, they must be coded to use both > of them. *That means that DO must also supply two addresses, not just one. > Yes? *If only one is provided by DO , then a stack underflow will occur.. > I.e., that implies that DO 's code must mirror the implementation of ?DO in > terms of placing addresses on the stack. *If LOOP and +LOOP didn't haveto > backfill in the conditional forward address from ?DO , then DO would be > simpler. > > (Just prior to me posting this, Ms. Rather posted a solution which doesn't > require both DO and ?DO putting two addresses onto the stack.) > > > [...] and the IF's compile-time info should be stored so > > that it will be resolved as if it were a LEAVE. > > Are you talking about the linked-list created "leave" and "rake" chaining > implementation of LEAVES? > > > Do you have LEAVE yet? > > No. > > > I'd implement that before ?DO. > > Why? > ISTM that the "leaves-rake" method is complicated. How complicate it is depends on how you implement it. If you implement it for simplicity, it can be as simple as postponing a THEN as long as loop count is greater than zero: : RAKE-LEAVES ( C: u1 u2 count*orig -- ) leave-count @ BEGIN ?DUP WHILE SWAP POSTPONE THEN REPEAT leave-count ! do-height ! ; > ISTM also that it doesn't fit well with the other > control-flow words. Quite, its a exceptional exit from the do-loop, and does not use the regular compile-time structure stack. > From what I can tell, it seems that ANS LEAVE also > requires a forward reference branch address that must be > resolved, like ?DO Yes, which is why if you have LEAVE already, the simplest way to do ? DO is to hook into that system. > I'm not sure yet how to work that into DO ?DO LOOP +LOOP yet. In that case, have DO drop a "0" on the stack before it drops its "dest", and have ?DO drop a "TRUE" on the stack after it postpones its "IF". Then at the right time in LOOP and +LOOP, you have: ... IF POSTPONE THEN THEN ... .... and you're set until you work out how you are going to handle LEAVE. |
|
|||
|
On 3/30/12 9:31 PM, Rod Pemberton wrote:
> "Elizabeth D. Rather"<erather@forth.com> wrote in message > news:sr6dnQSBkK-NNuvSnZ2dnUVZ_vednZ2d@supernews.com... >> On 3/30/12 1:46 PM, Josh Grams wrote: >>> Rod Pemberton wrote:<jl5cp3$tev$1@speranza.aioe.org> >>>> Does ?DO force DO 's definition to become bloated? >>> >>> It shouldn't change DO at all. >>> >>> ?DO should basically compile `2DUP<> IF DO`, and the IF's compile-time >>> info should be stored so that it will be resolved as if it were a LEAVE. >> >> Alternatively, the compile-time ?DO can compile a reference to the >> runtime ?DO which checks the stack arguments and, if necessary, discard >> the loop parameters and branch to the address beyond the next LOOP or >> +LOOP. Then compile a reference to the normal runtime for DO, which will >> be part of what gets skipped if necessary. >> >> In other words, keep these words suitably factored. Neither has to do >> the other's job. >> >> For example: >> >> : DO ( -- flag addr) >> POSTPONE (DO) 0 (BEGIN) ; IMMEDIATE >> >> : ?DO ( -- addr1 flag addr2) >> POSTPONE (?DO) (BEGIN) >> POSTPONE (DO) 1 (BEGIN) ; IMMEDIATE >> >> ...where (DO) and (?DO) are the run-time actions. (?DO) contains a >> forward branch which compile-time LOOP or +LOOP must resolve. (BEGIN) >> leaves on the compile-time stack an address for LOOP or +LOOP to branch >> back to, and a flag. >> > > Ok, make LOOP and +LOOP "smarter" or DO/?DO-aware ... I had decided against > attempting to pair them, in case there was some unforeseen issue leading to > a mismatch. But, that works or should. It's simple enough. The DO words and LOOP words are inevitably paired. That's why the standard uses special compile-time stack nomenclature 'do-orig' and 'do-dest' to describe them. And simple solutions are always best :-) The LOOP words don't have to be very smart, just fix the necessary address if there is one. 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." ================================================== |
|
|||
|
Elizabeth D. Rather wrote:
> The function of ?DO is simply to determine whether to proceed with DO or > not. So there's no need to incorporate DO's logic in ?DO or vice-versa. > Just compile ?DO followed by the runtime of DO, and all that will be > skipped if ?DO's test fires. "Simply.." 2DUP <> IF DO .. LOOP ELSE 2DROP THEN Too horrible for words.. Elegant is different. Hans Bezemer |
|
|||
|
On Mar 31, 3:31*am, "Rod Pemberton" <do_not_h...@noavailemail.cmm>
wrote: > Ok, make LOOP and +LOOP "smarter" or DO/?DO-aware ... *I had decided > against attempting to pair them, in case there was some unforeseen issue > leading to a mismatch. *But, that works or should. *It's simple enough. Well, you're patching an existing model, so that can complicate things compared to designing it to suit ... Wouldn't a simple state flag variable work? Something like the following, if (LOOP) and (+LOOP) include UNLOOP as part of their behavior? VARIABLE ?do? : 2DUP= ( x1 x2 -- x1 x2 flag ) 2DUP = ; : DO ?do? @ ?do? OFF [COMPILE] (DO) HERE 0 , ; IMMEDIATE : ?DO POSTPONE 2DUP= POSTPONE IF POSTPONE DO TRUE ?do? ! ; IMMEDIATE : COMPLETE-?DO ( x dest | x -- ) ?do? @ IF POSTPONE THEN THEN ?do? ! ; : LOOP POSTPONE (LOOP) , COMPLETE-?DO ; IMMEDIATE : +LOOP POSTPONE (+LOOP) , COMPLETE-?DO ; IMMEDIATE > My ?DO is putting two addresses onto the stack, one for the loop and one > for the forward branch that needs resolving. *Because of ?DO needing two > addresses and it "passing" both to LOOP and +LOOP , I changed DO to also > put two addresses onto the stack instead of only one. A variety of ways to implement it, but its probably not needed to have DO include a dummy jump that is never taken. |
|
|||
|
On Mar 31, 2:56*pm, Hans Bezemer <the.beez.spe...@gmail.com> wrote:
> Elizabeth D. Rather wrote: >> The function of ?DO is simply to determine whether to proceed with DO or >> not. So there's no need to incorporate DO's logic in ?DO or vice-versa. >> Just compile ?DO followed by the runtime of DO, and all that will be >> skipped if ?DO's test fires. > "Simply.." > * * * * 2DUP <> IF DO .. LOOP ELSE 2DROP THEN > Too horrible for words.. Elegant is different. From the text description, it sounds like the ?DO runtime, aka (?DO) or do_QDO would clean up the loop parameters before taking the branch, rather than laboriously compiling that process into each ?DO-LOOP: > Alternatively, the compile-time ?DO can compile a reference to the > runtime ?DO which checks the stack arguments and, if necessary, discard > the loop parameters and branch to the address beyond the next LOOP or > +LOOP. Then compile a reference to the normal runtime for DO, which will > be part of what gets skipped if necessary. |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|