Given a word w0 , I wish to know all words that uses w0.
To that end, first I need to know whether a word w1 uses
w0 or not.
There are two candidate cell patterns for w0 usage in w1.
These are:
'lica.... i or LIteral CAll 0 0 in nga.
'lica.... i in nga is #2049.
~~~#2049 'LICA.... const (LIteral_CAll_0_0_instruction
:lica....? (n-f) LICA.... eq? ;
~~~
'liju.... i or LIteral JUmp 0 0 in nga.
'liju.... i in nga is #1793.
~~~#1793 'LIJU.... const (LIteral_JUmp_0_0_instruction
:liju....? (n-f) LIJU.... eq? ;
~~~
The pattern? word will check for both.
~~~:pattern? [ lica....? ] [ liju....? ] bi or ;
~~~
If pattern is followed by w0's execution token xt0,
then w1 uses w0.
The pattern of two cells to be sought is
LICA.... (or LIJU....)
xt0
The name of w1 may be found by 'a1 d:lookup d:name
in which a1 is w1's address.
Variables Used contains a0 and In contains a1.
Make sure the word's class is class:word and not something
else, like class:primitive, class:data, etc.
~~~'Used var (a0
'In var (a1
:class:word? (a-f) d:class fetch &class:word eq? ;
:used (a-) dup !Used ;
:in (a-) dup !In ;
~~~
Set the code range to search for the pattern.
~~~'Start var
'End var
~~~
The start is the execution token.
~~~:start (-) @In d:xt !Start ;
~~~
The end is two cells before the first newer entry to the
dictionary.
If that cell is not lica..., then the next cell does not
hold an execution token.
The first newer entry may be found by d:new fetch .
~~~:d:new-old (a-aa)_returns_(This_0)_if_This_is_d:last
d:last dup-pair eq? (this_last_flag
[ drop #0 ] if; (exit_if_this_is_last (this_last
[ dup-pair d:link fetch (this_newer_this_new
eq? [ TRUE ] [ d:link fetch FALSE ] choose (this_newer_flag
] until (this_newer
swap d:link fetch ; (newer_old
:d:new (a-a) d:new-old drop ;
:end (-) @In d:new dup n:zero?
[ here #2 - ] [ dup #2 - n:max ] choose !End ;
~~~
Check if a pair of cells indicates that the word is used.
~~~:pair? (a-f) dup fetch pattern?
[ #1 + fetch @Used d:xt fetch eq? ] [ drop FALSE ] choose ;
~~~
~~~'Address var (head_address_of_the_pair_being_checked
'More var (TRUE_=_there_are_remaining_pairs_to_check
'Found var (TRUE_=_@In_used_@Used
:more (-) @Address @End lt? [ TRUE ] [ FALSE ] choose !More ;
:prepare (-) start end @Start !Address FALSE !Found more ;
:uses? (-f)_does_@In_use_@Used_?
prepare [
(pair-found @Address pair? [ &Found v:on ] if )
(more-to-check more &Address v:inc )
(condition-to-loop @Found not @More and ) ] while @Found ;
~~~
```:t (aa-) used in start end ;
:a 'a s:put ;
:b a 'b s:put ;
:c b 'c s:put ;
'b d:lookup in 'a d:lookup used
uses? n:put nl
```
Final product.
~~~:used-in (a-)
used
[ dup class:word?
[ in uses? [ @In d:name s:put sp ] if drop ] [ drop ] choose
] d:for-each drop ;
:d:used-in (s-) d:lookup used-in ;
~~~
```'a d:lookup used-in
```
Hide unnecessary words.
~~~'LICA.... d:lookup d:link fetch
'd:used-in d:lookup d:link store
~~~~
# Limitations
This only searches visible words. Any headers that are hidden
from the dictionary are no longer visible. So:
:foo dup * + ;
{{
:test #2 #3 foo ;
----reveal--
:bar test n:put nl ;
}}
'foo d:used-in
This will not see the use of `foo` in `test` as the header for
`test` is not visible after the closing `}}`.