Retro's listener will call notfound when a word name is not found, and when the input token can not be converted to a number in the current base. Prior to 10.6, notfound just displays some sort of error message. In 10.6, it has been rewritten and extended to do additional checks related to prefixes.
The code:
label: ___ " ___" $,
t: get ( $-$ ) dup, @, ___ # 2 # +, !, 1+, ;
t: try ( - )
TIB # get find
if d->xt @, ___ # find
if dup, d->xt @, swap, d->class @, with-class
pop, pop, 2drop ; then
drop,
then drop, ;
t: filter ( - ) TIB # getLength 2 # >if try then ;
t: notfound ( - ) filter char: ? # emit cr ;
Ok, first thing to note is that the syntax looks a bit unusual. This is written using the metacompiler, which introduces some new rules:
- t: instead of :
- # following numbers/constants
- , following opcode names
Getting this out of the way, we can proceed to break it down.
label: ___ " ___" $,
This line creates a constant pointing to a string containing three underscores. This string is modified later, with the last underscore replaced by a prefix character.
t: get ( $-$ ) dup, @, ___ # 2 # +, !, 1+, ;
The get receives a string from the stack; moves the first character into the last position of ___ and then returns the rest of the provided string.
t: try ( - )
TIB # get find
if d->xt @, ___ # find
if dup, d->xt @, swap, d->class @, with-class
pop, pop, 2drop ; then
drop,
then drop, ;
This is the largest part of the prefix handling. It passes the token in tib to get and then searches for the name (sans the prefix character) in the dictionary.
If found, the xt of the word is returned, and a search is done for __X, where X is the prefix character. If this is found, the xt and class of the prefix handler are pushed to the stack, and with-class is called to execute everything. Also, if found, control is passed directly back to the listener.
If not found, the stack is cleaned up and control passes back to the notfound handler.
t: filter ( - ) TIB # getLength 2 # >if try then ;
To ensure that the prefixes are not searched for with single character tokens we have a simple filter word. A subtle note here: >if and in Retro are inclusive, so this is actually checking for 2 or greater length, not length greater than 2.
t: notfound ( - ) filter char: ? # emit cr ;
And finally the notfound word itself. It calls filter, which then calls try, and so on. If the token + prefix are not found, a ? is displayed and control is returned to the listener.
Ok, now for the prefixes that are provided by default:
t: __& ( a-n ) .data ;
Usage: &name
Action: Return the address (xt) of the word.
Similar To: ['] name
t: __+ ( a- ) .data ' +! # .word ;
Usage: +name
Action: Add a value from the stack to the value stored at name's xt field.
Similar To: name +!
t: __- ( a- ) .data ' -! # .word ;
Usage: -name
Action: Subtract a value from the value stored at name's xt field.
Similar To: name -!
t: __@ ( a-n ) .data ' @ # .word ;
Usage: @name
Action: Return the value stored at the address (xt) field of the word.
Similar To: name @
t: __! ( a-n ) .data ' ! # .word ;
Usage: !name
Action: Store a value to the address field of a name
Similar To: name !
If you want to create your own prefixes, you can do this as well. For a simple example:
: __~ ( a- ) .data ` :see ; immediate prefix
This will create a new ~ prefix that shows decompiled code for the word. Note the prefix at the end of the definition. This is optional, but moves the new prefix handler to the prefixes vocabulary, allowing it to be grouped cleanly with the other prefixes.
No comments:
Post a Comment