version 1.58, 2000/07/14 09:24:06
|
version 1.59, 2000/07/16 20:09:37
|
Line 309 Defining Words
|
Line 309 Defining Words
|
* Aliases:: |
* Aliases:: |
* Supplying names:: |
* Supplying names:: |
|
|
|
User-defined Defining Words |
|
|
|
* CREATE..DOES> applications:: |
|
* CREATE..DOES> details:: |
|
* Advanced does> usage example:: |
|
|
Interpretation and Compilation Semantics |
Interpretation and Compilation Semantics |
|
|
* Combined words:: |
* Combined words:: |
Line 351 Programming Tools
|
Line 357 Programming Tools
|
* Assertions:: Making your programs self-checking. |
* Assertions:: Making your programs self-checking. |
* Singlestep Debugger:: Executing your program word by word. |
* Singlestep Debugger:: Executing your program word by word. |
|
|
|
Assembler and Code Words |
|
|
|
* Code and ;code:: |
|
* Common Assembler:: Assembler Syntax |
|
* Common Disassembler:: |
|
* 386 Assembler:: Deviations and special cases |
|
* Alpha Assembler:: Deviations and special cases |
|
* MIPS assembler:: Deviations and special cases |
|
* Other assemblers:: How to write them |
|
|
Locals |
Locals |
|
|
* Gforth locals:: |
* Gforth locals:: |
Line 6271 locals declarations for stack effect spe
|
Line 6287 locals declarations for stack effect spe
|
@menu |
@menu |
* CREATE..DOES> applications:: |
* CREATE..DOES> applications:: |
* CREATE..DOES> details:: |
* CREATE..DOES> details:: |
* Advanced does> usage:: |
* Advanced does> usage example:: |
@end menu |
@end menu |
|
|
@node CREATE..DOES> applications, CREATE..DOES> details, User-defined Defining Words, User-defined Defining Words |
@node CREATE..DOES> applications, CREATE..DOES> details, User-defined Defining Words, User-defined Defining Words |
Line 6321 DOES> ( n2 -- n1+n2 )
|
Line 6337 DOES> ( n2 -- n1+n2 )
|
-2 curry+ 2- |
-2 curry+ 2- |
@end example |
@end example |
|
|
@node CREATE..DOES> details, Advanced does> usage, CREATE..DOES> applications, User-defined Defining Words |
@node CREATE..DOES> details, Advanced does> usage example, CREATE..DOES> applications, User-defined Defining Words |
@subsubsection The gory details of @code{CREATE..DOES>} |
@subsubsection The gory details of @code{CREATE..DOES>} |
@cindex @code{CREATE} ... @code{DOES>}, details |
@cindex @code{CREATE} ... @code{DOES>}, details |
|
|
Line 6379 CREATE name EXECUTE ( ... -- ... )
|
Line 6395 CREATE name EXECUTE ( ... -- ... )
|
|
|
doc->body |
doc->body |
|
|
@node Advanced does> usage, , CREATE..DOES> details, User-defined Defining Words |
@node Advanced does> usage example, , CREATE..DOES> details, User-defined Defining Words |
@subsubsection Advanced does> usage |
@subsubsection Advanced does> usage example |
|
|
|
The MIPS disassembler (@file{arch/mips/disasm.fs}) contains many words |
|
for disassembling instructions, that follow a very repetetive scheme: |
|
|
|
@example |
|
:noname @var{disasm-operands} s" @var{inst-name}" type ; |
|
@var{entry-num} cells @var{table} + ! |
|
@end example |
|
|
|
Of course, this inspires the idea to factor out the commonalities to |
|
allow a definition like |
|
|
|
@example |
|
@var{disasm-operands} @var{entry-num} @var{table} define-inst @var{inst-name} |
|
@end example |
|
|
|
The parameters @var{disasm-operands} and @var{table} are usually |
|
correlated. Moreover, there existed code defining instructions like |
|
this: |
|
|
|
@example |
|
@var{entry-num} @var{inst-format} @var{inst-name} |
|
@end example |
|
|
|
This code comes from the assembler and resides in |
|
@file{arch/mips/insts.fs}. |
|
|
|
So I had to define the @var{inst-format} words that performed the scheme |
|
above when executed. At first I chose to use run-time code-generation: |
|
|
|
@example |
|
: @var{inst-format} ( entry-num "name" -- ; compiled code: addr w -- ) |
|
:noname Postpone @var{disasm-operands} |
|
name Postpone sliteral Postpone type Postpone ; |
|
swap cells @var{table} + ! ; |
|
@end example |
|
|
|
Note that this supplies the other two parameters of the scheme above. |
|
|
|
An alternative would have been to write this using |
|
@code{create}/@code{does>}: |
|
|
|
@example |
|
: @var{inst-format} ( entry-num "name" -- ) |
|
here name string, ( entry-num c-addr ) \ parse and save "name" |
|
noname create , ( entry-num ) |
|
lastxt swap cells @var{table} + ! |
|
does> ( addr w -- ) |
|
\ disassemble instruction w at addr |
|
@@ >r |
|
@var{disasm-operands} |
|
r> count type ; |
|
@end example |
|
|
|
Somehow the first solution is simpler, mainly because it's simpler to |
|
shift a string from definition-time to use-time with @code{sliteral} |
|
than with @code{string,} and friends. |
|
|
|
I wrote a lot of words following this scheme and soon thought about |
|
factoring out the commonalities among them. Note that this uses a |
|
two-level defining word, i.e., a word that defines ordinary defining |
|
words. |
|
|
|
This time a solution involving @code{postpone} and friends seemed more |
|
difficult (try it as an exercise), so I decided to use a |
|
@code{create}/@code{does>} word; since I was already at it, I also used |
|
@code{create}/@code{does>} for the lower level (try using |
|
@code{postpone} etc. as an exercise), resulting in the following |
|
definition: |
|
|
|
@example |
|
: define-format ( disasm-xt table-xt -- ) |
|
\ define an instruction format that uses disasm-xt for |
|
\ disassembling and enters the defined instructions into table |
|
\ table-xt |
|
create 2, |
|
does> ( u "inst" -- ) |
|
\ defines an anonymous word for disassembling instruction inst, |
|
\ and enters it as u-th entry into table-xt |
|
2@@ swap here name string, ( u table-xt disasm-xt c-addr ) \ remember string |
|
noname create 2, \ define anonymous word |
|
execute lastxt swap ! \ enter xt of defined word into table-xt |
|
does> ( addr w -- ) |
|
\ disassemble instruction w at addr |
|
2@@ >r ( addr w disasm-xt R: c-addr ) |
|
execute ( R: c-addr ) \ disassemble operands |
|
r> count type ; \ print name |
|
@end example |
|
|
|
Note that the tables here (in contrast to above) do the @code{cells +} |
|
by themselves (that's why you have to pass an xt). This word is used in |
|
the following way: |
|
|
|
@example |
|
' @var{disasm-operands} ' @var{table} define-format @var{inst-format} |
|
@end example |
|
|
|
In terms of currying, this kind of two-level defining word provides the |
|
parameters in three stages: first @var{disasm-operands} and @var{table}, |
|
then @var{entry-num} and @var{inst-name}, finally @code{addr w}, i.e., |
|
the instruction to be disassembled. |
|
|
|
Of course this did not quite fit all the instruction format names used |
|
in @file{insts.fs}, so I had to define a few wrappers that conditioned |
|
the parameters into the right form. |
|
|
|
If you have trouble following this section, don't worry. First, this is |
|
involved and takes time (and probably some playing around) to |
|
understand; second, this is the first two-level |
|
@code{create}/@code{does>} word I have written in seventeen years of |
|
Forth; and if I did not have @file{insts.fs} to start with, I may well |
|
have elected to use just a one-level defining word (with some repeating |
|
of parameters when using the defining word). So it is not necessary to |
|
understand this, but it may improve your understanding of Forth. |
|
|
|
|
@node Deferred words, Aliases, User-defined Defining Words, Defining Words |
@node Deferred words, Aliases, User-defined Defining Words, Defining Words |
Line 8879 suite that contains all instructions. O
|
Line 9008 suite that contains all instructions. O
|
easy. For actual coding you can take a look at |
easy. For actual coding you can take a look at |
@file{arch/mips/disasm.fs} to get some ideas on how to use data for both |
@file{arch/mips/disasm.fs} to get some ideas on how to use data for both |
the assembler and disassembler, avoiding redundancy and some potential |
the assembler and disassembler, avoiding redundancy and some potential |
bugs. You can also look at that file (and @pxref{Advanced does> usage}) |
bugs. You can also look at that file (and @pxref{Advanced does> usage |
to get ideas how to factor a disassembler. |
example}) to get ideas how to factor a disassembler. |
|
|
Start with the disassembler, because it's easier to reuse data from the |
Start with the disassembler, because it's easier to reuse data from the |
disassembler for the assembler than the other way round. |
disassembler for the assembler than the other way round. |