I'm looking for a word that CREATEs a dictionary entry named by a string
in memory, rather than by the next word in the input stream. Nothing
jumped out at me from the ANS Forth document as being the word I want.
Is there a standard word that does this?
Thanks,
-- Joe
--
"We sat and watched as this whole <-- (Died Pretty -- "Springenfall")
blue sky turned to black..."
... Re-defeat Bush in '04.
--
pub 1024D/BA496D2B 2004-05-14 Joseph A Knapka
Key fingerprint = 3BA2 FE72 3CBA D4C2 21E4 C9B4 3230 94D7 BA49 6D2B
If you really want to get my attention, send mail to
jknapka .at. kneuro .dot. net.
> Hi folks,
>
> I'm looking for a word that CREATEs a dictionary entry named by a string
> in memory, rather than by the next word in the input stream. Nothing
> jumped out at me from the ANS Forth document as being the word I want.
> Is there a standard word that does this?
>
I don't know if it's standard, but in gforth you could use nextname
it's ( adr len --- ) and the next defining word uses that name, so f.e.
S" test" nextname create
does what you want
Michael
But if you still want to name every object you create, you can use
EVALUATE to execute a string containing "CREATE " followed by the name
of the word you want to create.
-Billy
Ah hah! That will do it, thanks.
Interesting that you should assume I'm building an OO exension :-) I'm
actually only building data-structure-defining words - specifically
slot accessors -- and I've got them working, but I'm not satisfied. My
current code is only four lines long:
0 value soffset
: defstruct 0 to soffset ;
: struct-field create soffset >r soffset + to soffset r> , does> @ + ;
: endstruct create soffset , does> create @ allot ;
But it has to be used like this:
\ Define the point struct:
defstruct
1 cells struct-field point-x
1 cells struct-field point-y
endstruct point
\ Build a point struct:
point p1
21 p1 point-x !
57 p1 point-y !
It feels wrong to have to repeat the struct name for every accessor.
What I'd like to do is capture the structure name at the beginning,
and automagically prepend the structure name to the accessor names,
like Lisp's defstruct:
defstruct point ( Save struct name somewhere. )
1 cells struct-field x ( Create point-x accessor. )
1 cells struct-field y ( Create point-y accessor. )
endstruct ( Create "point" constructor from saved struct name. )
(There may be a standard way to do this sort of structure-defining
stuff, but I'm having fun figuring it out, so don't pester me about
that, please!)
Cheers,
I disagree with your feeling. ;-)
The fields are part of whatever is created by point
and you should specify what they are part of.
What with:
\ first we have x coordinates
1 2
\ then y (got them in this order from somewhere)
3 4
point p1
point p2
\ now first set y coordinates
p1 point-y !
p2 point-y !
\ then set x coordinates
p1 point-x !
p2 point-x !
You might add a simple explicit WITH construct
like in PASCAL. (or was it MODULA?)
value with
: struct-with-field
create soffset >r soffset + to soffset r> ,
does> @ with + ;
point p1
p1 to with
12 point-x !
34 point-y !
(Not tested!)
But mind, that creates context depedency that is not
visible at the point of use.
Also you might make a point set "with" automatically
: endstruct create soffset ,
does> create @ allot \ this is executed by point
does> to with ; \ this is executed by p1 p2, ...
(Not tested aganin)
Or use deferred word and make "with" switch between
this implementation and yours.
I think that's enough stuff to experiment with for now. ;-)
Have a nice day,
Uwe
Well, it will usually do it, but when it fails, that will be all the
more surprising. With EVALUATE you make yourself dependent on the
search order, and even if the right wordlist is on top, you rely on
the fact that the EVALUATE you want is not shadowed by another one
(for other uses of EVALUATE, BASE is also a problem). There are ways
to work around these issues, but they are quite complex.
Apart from the NEXTNAME that has been mentioned already, and which is
quite special-purpose, there is also a more general word that has been
proposed, and is implemented in Gforth-0.6 under the name
EXECUTE-PARSING. In your case you would use it like this:
( addr u ) ['] create execute-parsing
EXECUTE-PARSING makes the string into the current input stream, and
then EXECUTEs the xt you pass it; that xt is thus allowed to parse
from the string. Afterwards the EXECUTE the original input stream is
restored.
>Interesting that you should assume I'm building an OO exension :-) I'm
>actually only building data-structure-defining words - specifically
>slot accessors -- and I've got them working, but I'm not satisfied. My
>current code is only four lines long:
>
> 0 value soffset
> : defstruct 0 to soffset ;
> : struct-field create soffset >r soffset + to soffset r> , does> @ + ;
> : endstruct create soffset , does> create @ allot ;
You can make this shorter by keeping the offset on the stack instead
of the soffset variable.
> 57 p1 point-y !
>
>It feels wrong to have to repeat the struct name for every accessor.
Consider the field words as conversion words, where you specify the
input before the "-", and the output afterwards. You can also think
of it as a kind of Hungarian notation.
In any case, I don't see a good way around that, at least for the
uses. All proposals I have seen rely on search order hacking or
similar stuff, each with its own problems that are worse IMO than the
problem they are trying to solve. You would need static type tracking
for a relatively clean solution, and that would certainly turn Forth
into a quite-different language.
- 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
EuroForth 2004: http://www.complang.tuwien.ac.at/anton/euroforth2004/
Deadline (refereed): August 28, 2004; Conference: November 19-21, 2004
1. EVALUATE is redefined.
What is the problem here? If it has been redefined to do something
completely different, yes, there is a problem. But this would be
extremely bad style Forth, and the remedy lies with fixing the EVALUATE,
not its usage. If it has been redefined to do its original work plus
enhancements, then this should be transparent.
2. Problems with BASE. What preoblems?
> Apart from the NEXTNAME that has been mentioned already, and which is
> quite special-purpose, there is also a more general word that has been
> proposed, and is implemented in Gforth-0.6 under the name
> EXECUTE-PARSING. In your case you would use it like this:
>
> ( addr u ) ['] create execute-parsing
>
> EXECUTE-PARSING makes the string into the current input stream, and
> then EXECUTEs the xt you pass it; that xt is thus allowed to parse
> from the string. Afterwards the EXECUTE the original input stream is
> restored.
>
When using CREATE or : from string, I usually want to use the most
recent definitions of these defining words, in the current context. In
these cases, using the EVALUATE version is fine (for my uses). In case
the original CREATE or : are needed, I agree that execute-parsing is a
better solution. Unfortunately, it is not ANS definable in a pure way
(without EVALUATE).
This is how I have these words defined in my utility file:
( note: : grab allocate abort" .." ; : loose free abort" .." ; )
\ EVALUATE the concatenated string2 string1
\
: concat-eval ( addr1 len1 addr2 len2 -- )
DUP 3 PICK + \ -- addr1 len1 addr2 len2 len1+len2
DUP >R CHARS grab \ -- addr1 len1 addr2 len2 c-addr
DUP >R SWAP DUP >R CMOVE \ -- addr len ; string2 placed at c-addr
R> CHARS R@ + \ -- addr1 len1 addr3
SWAP CMOVE \ append the string1 to string2
R> R> OVER >R \ -- c-addr len1+len2
EVALUATE \ evaluate string2+string1
R> loose \ release c-addr
;
\ same as CREATE, but take a forth string from stack for name
\
: $create ( addr len -- )
S" CREATE " concat-eval
;
\ same as :, but takes a forth string from stack for name
\
: $: ( addr len -- )
S" : " concat-eval
;
[undefined] execute-parsing
[IF]
\ make the string the current input and execute the xt
\
: execute-parsing ( addr len xt -- )
-rot
S" EXECUTE " concat-eval
;
[THEN]
> > But if you still want to name every object you create, you can use
> > EVALUATE to execute a string containing "CREATE " followed by the
name
> > of the word you want to create.
> Ah hah! That will do it, thanks.
Cool :-). And BTW, the danger is only if someone redefines the word
"CREATE". You can (and must) decide for yourself whether that's a real
danger. I've used this technique in situations where there was _much_
more danger. IMO the only real danger is when you use words that you've
defined in an EVALUATE string.
> It feels wrong to have to repeat the struct name for every accessor.
> What I'd like to do is capture the structure name at the beginning,
> and automagically prepend the structure name to the accessor names,
> like Lisp's defstruct:
> defstruct point ( Save struct name somewhere. )
On the stack.
> 1 cells struct-field x ( Create point-x accessor. )
> 1 cells struct-field y ( Create point-y accessor. )
> endstruct ( Create "point" constructor from saved struct name. )
You could also create the struct name in 'defstruct', and allot space
in it for a pointer to the structure description.
> (There may be a standard way to do this sort of structure-defining
> stuff, but I'm having fun figuring it out, so don't pester me about
> that, please!)
As you've seen, it's pretty simple, so there's no limit on the number
of ways to do it.
> -- Joe
-Billy
> Joe Knapka wrote:
> > defstruct point ( Save struct name somewhere. )
>
> On the stack.
Don't I need to copy the parsed structure name to a safe place, to
avoid it being overwritten by further I/O activity?
Sorry, replace "EVALUATE" in some places above with "CREATE".
Ok, for elaboration:
Reliance on the search-order:
: foo ( -- )
s" create test" evaluate ;
\ ... much later ...
wordlist constant x
get-current x set-current
: bar foo ;
set-current
\ ... much later ...
x 1 set-order
bar \ "create" unknown
Reliance on non-shadowing
: foo ( -- )
s" create test" evaluate ;
: create ( -- )
." funny create" ;
foo \ prints "funny create", then tries to interpret "test"
Another nice one for shadowing is this:
: again s" 0 until" evaluate ; immediate
: until s" 0= if [ 1 cs-roll ] again then" evaluate ; immediate
: foo begin again ; \ tries to recurse endlessly
Note that the definition of AGAIN above comes from Wil Baden, one of
the fans of using EVALUATE in this way.
>2. Problems with BASE. What preoblems?
: ten+ s" 10 +" evaluate ; immediate
0 ten+ . \ 10
hex
0 ten+ decimal . \ 16
hex
: foo ten+ ;
decimal
0 foo . \ 16
Oh, and there is
3. Problems with STATE
: my-+ s" +" evaluate ;
: bar 1 2 my-+ . ; immediate
bar
: boing bar ; \ unbalanced stack at compile time
In the way that Wil Baden uses EVALUATE-based macros, he gets around
the last problem by making all of these macros immediate right away,
but that makes the context resolution even more intereting (neither
the static context nor the run-time context is used, but a compilation
context); moreover, this restriction cannot be used for stuff like our
CREATE problem here.
> When using CREATE or : from string, I usually want to use the most
>recent definitions of these defining words, in the current context.
\ context A
: foo ... s" create " ... evaluate ;
: bar ... ['] create execute-parsing ;
\ ...
\ context B
foo
bar
What is the current context for the CREATE? Context A or context B?
In Forth the usual thing is to use the context valid when the word is
compiled, i.e., context A. This makes sense, because the user of FOO
or BAR should not be burdened with dependencies coming from
implementation details of FOO and BAR (why should the user care that
FOO uses CREATE, not some other defining word?). Why should this way
of dealing with context lose its validity when we want to pass a
string to a parsing word?
> In
>these cases, using the EVALUATE version is fine (for my uses). In case
>the original CREATE or : are needed, I agree that execute-parsing is a
>better solution. Unfortunately, it is not ANS definable in a pure way
>(without EVALUATE).
It can be defined in ANS Forth in a safe way with EVALUATE, though (at
least I think so, EVALUATE is so pitfally that I am not absolutely
sure); here's an untested sketch:
wordlist constant ep-wordlist
get-current ep-wordlist set-current
: execute-parsing-stage2 ( xt -- )
previous \ restore search order
catch \ execute xt
refill drop \ throw away the rest of the line,
\ so EVALUATE won't do anything else
throw \ throw the ball caught by CATCH onwards
; immediate \ make it work in either STATE
set-current
: >order ( wid -- )
\ push on search-order
>r get-order r> swap 1+ set-order ;
: execute-parsing ( ... addr u xt -- ... )
rot rot s" execute-parsing-stage2 " 2swap concat-strings ( xt addr1 u1 )
ep-wordlist >order \ make ep-wordlist the first one searched
evaluate \ interpret "execute-parsing-stage2 <addr u>"
\ ... free string
;