to
etc. ¶When you define a word x, you can set its execution semantics
with set-does>
(see User-defined defining words using create) or set-execute
(see Header methods). But you can
also change the semantics of
to x \ aka ->x +to x \ aka +>x addr x action-of x \ aka `x defer@ is x \ aka `x defer!
This is all achieved through a common mechanism described in this
section. As an example, let’s define dvalue
(it behaves in
Gforth exactly like 2value
, see Values). First, we need a
table of the various to
-like actions:
: d+! ( d addr -- ) dup >r 2@ d+ r> 2! ; \ to +to addr action-of is to-table: d!-table 2! d+! n/a n/a n/a
This defines a table d!-table
with a to
and a +to
action, and no action for addr
, action-of
and is
;
i.e., for our x defined with dvalue
, if you addr
x
, you will get an error message. At the end of the line you
can leave trailing n/a
s away, but here we show them for
completeness.
The entries in the table are words that get an address on the
top-of-stack. They possibly also expect some additional data deeper
in the stack, but that is data that is provided in the usual use of
the word. E.g., in the case of dvalue
, the expectation is that
you put a double-cell d on the stack before you do a to
x
, and that d and the address
where it should be stored is eventually passed to 2!
.
In the case of dvalue
, the address is computed from the xt of
x with >body
. In order to let that be known to the
system, you write
`>body d!-table to-class: dvalue-to
This defines the method implementations of the methods behind
to
, +to
and addr
, and the methods defer@
,
and defer!
. The reason for defining the methods in two steps
(by first defining the table) is that the same table can be used for
several to-classes; e.g., !-table
is used for defining
value-to
(used for value
), but also for uvalue-to
used for defining uvalue
(see Task-local data) and
to-w:
(used for the default (w:
) locals).
>body
is appropriate for words with storage in the dictionary,
such as value
. But, e.g., for storage in user (task-local)
storage (e.g., uvalue
), you use >uvalue
instead. The
general case is that the system pushes the xt of x, and then
executes the xt that has been passed to to-class:
. This xt may
also consume one or more additional values passed on the stack (e.g.,
for value-flavoured struct fields, xt consumes the address of the
struct right below the xt); its overall stack effect is ( ... xt
-- addr )
.
Now you can define
: dvalue ( d "name" -- ) create 2, `2@ set-does> `dvalue-to set-to ;
Here the set-to
changes the created word name to use the
methods from dvalue-to
for implementing to
and
+to
(and the others, but they are defined to deliver errors).
Now you can define words with dvalue
and use them:
#5. dvalue x #2. +to x x d. \ prints "7 "
The +to x
first pushes the xt of x
, then performs
>body
(provided in the definition of dvalue-to
), and
finally performs the d+!
provided in the d!-table
.
You may want to define another defining word dvarue
that is
like dvalue
, but also supports addr
(see Varues),
usually using [noop]
as implementation for the part of
addr
that already receives the address on the stack. Gforth
provides >to+addr-table
; it takes a table address on the stack
and creates a new table with the same entries, except that the
addr
entry is replaced by [noop]
. So you can now define
dvarue
as follows:
d!-table >to+addr-table d!a-table `>body d!a-table to-class: dvarue-to : dvarue ( d "name" -- ) create 2, `2@ set-does> `dvarue-to set-to ;
These are the words mentioned above:
to-table:
( "name" "to-word" "+to-word" "addr-word" "action-of-word" "is-word" – ) gforth-experimental “to-table-colon”
Create a table name with entries for TO
, +TO
,
ADDR
, ACTION-OF
, and IS
. The words for
these entries are called with xt on the stack, where xt
belongs to the word behind to
(or +to
etc.). Use
n/a
to mark unsupported operations. Unsupported
operations can be left away at the end of the line.
n/a
( – ) gforth-experimental “not-available”
This word can be ticked, but throws an “Operation not supported” exception on interpretation and compilation. Use this for methods etc. that aren’t supported.
>to+addr-table:
( table-addr "name" – ) gforth-experimental “to-to-plus-addr-table-colon”
Name is a copy of the table at table-addr, but in
name the ADDR
-method is supported
[noop]
( – ) gforth-experimental “bracket-noop”
Does nothing, both when executed and when compiled.
to-class:
( xt table "name" – ) gforth-experimental “to-class-colon”
Create a to-class implementation name, where xt
( ... xt -- addr )
computes the address to access the
data, and table (created with to-table:
) contains
the words for accessing it.
>uvalue
( xt – addr ) gforth-internal “to-uvalue”
Xt is the xt of a word x defined with uvalue
;
addr is the address of the data of x in the current
task. This word is useful for building, e.g., uvalue
.
Do not use it to circumvent that you cannot get the address of
a uvalue with addr
; in the future Gforth may perform
optimizations that assume that uvalues can only be accessed
through their name.
set-to
( to-xt – ) gforth-1.0 “set-to”
Changes the implementations of the to-class methods of the most recently defined word to come from the to-class that has the xt to-xt.