Krishna Myneni
2022-10-10 15:44:20 UTC
I've written Forth code (below) to demonstrate keeping track of word
dependencies using a Forth system capable of defining dual-semantics
words. Here I use Gforth for the example. I believe the following may
also be doable on VFX, using its NDCS: word. The other requirements of
the system are that the name token (nt) of the last word definition is
accessible, and that there is a mechanism to define a closure.
A word definition may be immediately followed by the word TRACK-DEPS
which will set its compilation semantics to not only compile its
interpretation semantics but also to add an entry into a dependency tree
to keep track of the words into which it is compiled. For example,
: FOO ." foo" ; TRACK-DEPS
: T1 foo ;
The word SHOW-DEPS prints the names of all words in which FOO is compiled.
s" foo" SHOW-DEPS \ prints T1
To continue,
: BAR ." bar" ; TRACK-DEPS
: T2 foo bar ;
s" foo" SHOW-DEPS \ prints the list: T2 T1
s" bar" SHOW-DEPS \ prints the list: T2
With the other definitions in the example code, it should be possible to
follow the entire dependency tree branch which terminates on a word for
which TRACK-DEPS has been applied (this assumes all of the nodes leading
to the word are also being tracked).
For simplicity, the dependency tree is implemented as a fixed size
table. This is not memory efficient and flexible enough for real use,
but is suitable for a demonstration. A tree structure should be used for
actual applications. The main point is to show that being able to set
the compilation semantics for a word independently allows for
capabilities which are likely not possible (or considerably more
difficult) in Forth source on a single-xt + immediate flag system only.
--
Krishna Myneni
dependencies.4th
-----------------
\ dependencies.4th
\
\ Demonstrate tracking first-level word dependencies
\ in a dual-xt system.
\
\ K. Myneni, 2022-10-10
\
\ This program is written for Gforth. It uses the following
\ non-standard words
\
\ LATESTNT ( -- nt )
\ SET-COMPSEM ( xt -- )
\ [N:D ( x -- )
require set-compsem.fs
synonym a@ @
100 constant MAX-TRACKS
64 constant MAX-DEPS
MAX-TRACKS MAX-DEPS * cells constant MAX-DTABLE-SIZE
create DEPENDENCY-TABLE MAX-DTABLE-SIZE allot
DEPENDENCY-TABLE MAX-DTABLE-SIZE erase
: th-track ( u -- a )
DEPENDENCY-TABLE swap MAX-DEPS * cells + ;
0 value curr-track
: get-track ( nt -- n ) \ return -1 if not found
curr-track 0 ?DO
I th-track a@ \ nt nt-track
over = IF drop I UNLOOP EXIT THEN
LOOP
drop -1 ;
: track-dependency ( nt -- )
curr-track th-track !
1 curr-track + to curr-track ;
: add-dependency ( nt-track nt-newdep -- )
swap get-track dup 0< IF
." Not tracking." cr abort
ELSE
th-track \ -- nt-dep a
BEGIN cell+ dup a@ 0= UNTIL !
THEN ;
\ Track first-level dependencies for last defined word
: track-deps ( -- )
latestnt dup track-dependency
[n:d dup name>interpret compile, latestnt add-dependency ;]
set-compsem ;
0 value ndeps
: what-requires? ( nt-track -- nt1 nt2 ... u | 0 )
0 to ndeps
get-track dup 0< IF
drop 0
ELSE
th-track cell+ \ -- a
BEGIN
dup a@ dup \ -- a nt|0 nt|0
WHILE
swap
ndeps 1+ to ndeps
cell+
REPEAT
2drop ndeps
THEN ;
: show-deps ( caddr u -- )
find-name ?dup IF
what-requires?
0 ?DO cr name>string type LOOP cr
then ;
0 [IF] \ Demonstration
\ Define two words for which first-level deps will be tracked
: foo ." foo" ; track-deps
: bar ." bar" ; track-deps
foo cr
bar cr
s" foo" show-deps \ list of words dependent on FOO is empty
s" bar" show-deps \ list of words dependent on BAR is empty
: t1 foo ;
: t2 foo bar ;
s" foo" show-deps \ shows T1 and T2 are dependent on FOO
s" bar" show-deps \ shows T2 is dependent on BAR
[THEN]
dependencies using a Forth system capable of defining dual-semantics
words. Here I use Gforth for the example. I believe the following may
also be doable on VFX, using its NDCS: word. The other requirements of
the system are that the name token (nt) of the last word definition is
accessible, and that there is a mechanism to define a closure.
A word definition may be immediately followed by the word TRACK-DEPS
which will set its compilation semantics to not only compile its
interpretation semantics but also to add an entry into a dependency tree
to keep track of the words into which it is compiled. For example,
: FOO ." foo" ; TRACK-DEPS
: T1 foo ;
The word SHOW-DEPS prints the names of all words in which FOO is compiled.
s" foo" SHOW-DEPS \ prints T1
To continue,
: BAR ." bar" ; TRACK-DEPS
: T2 foo bar ;
s" foo" SHOW-DEPS \ prints the list: T2 T1
s" bar" SHOW-DEPS \ prints the list: T2
With the other definitions in the example code, it should be possible to
follow the entire dependency tree branch which terminates on a word for
which TRACK-DEPS has been applied (this assumes all of the nodes leading
to the word are also being tracked).
For simplicity, the dependency tree is implemented as a fixed size
table. This is not memory efficient and flexible enough for real use,
but is suitable for a demonstration. A tree structure should be used for
actual applications. The main point is to show that being able to set
the compilation semantics for a word independently allows for
capabilities which are likely not possible (or considerably more
difficult) in Forth source on a single-xt + immediate flag system only.
--
Krishna Myneni
dependencies.4th
-----------------
\ dependencies.4th
\
\ Demonstrate tracking first-level word dependencies
\ in a dual-xt system.
\
\ K. Myneni, 2022-10-10
\
\ This program is written for Gforth. It uses the following
\ non-standard words
\
\ LATESTNT ( -- nt )
\ SET-COMPSEM ( xt -- )
\ [N:D ( x -- )
require set-compsem.fs
synonym a@ @
100 constant MAX-TRACKS
64 constant MAX-DEPS
MAX-TRACKS MAX-DEPS * cells constant MAX-DTABLE-SIZE
create DEPENDENCY-TABLE MAX-DTABLE-SIZE allot
DEPENDENCY-TABLE MAX-DTABLE-SIZE erase
: th-track ( u -- a )
DEPENDENCY-TABLE swap MAX-DEPS * cells + ;
0 value curr-track
: get-track ( nt -- n ) \ return -1 if not found
curr-track 0 ?DO
I th-track a@ \ nt nt-track
over = IF drop I UNLOOP EXIT THEN
LOOP
drop -1 ;
: track-dependency ( nt -- )
curr-track th-track !
1 curr-track + to curr-track ;
: add-dependency ( nt-track nt-newdep -- )
swap get-track dup 0< IF
." Not tracking." cr abort
ELSE
th-track \ -- nt-dep a
BEGIN cell+ dup a@ 0= UNTIL !
THEN ;
\ Track first-level dependencies for last defined word
: track-deps ( -- )
latestnt dup track-dependency
[n:d dup name>interpret compile, latestnt add-dependency ;]
set-compsem ;
0 value ndeps
: what-requires? ( nt-track -- nt1 nt2 ... u | 0 )
0 to ndeps
get-track dup 0< IF
drop 0
ELSE
th-track cell+ \ -- a
BEGIN
dup a@ dup \ -- a nt|0 nt|0
WHILE
swap
ndeps 1+ to ndeps
cell+
REPEAT
2drop ndeps
THEN ;
: show-deps ( caddr u -- )
find-name ?dup IF
what-requires?
0 ?DO cr name>string type LOOP cr
then ;
0 [IF] \ Demonstration
\ Define two words for which first-level deps will be tracked
: foo ." foo" ; track-deps
: bar ." bar" ; track-deps
foo cr
bar cr
s" foo" show-deps \ list of words dependent on FOO is empty
s" bar" show-deps \ list of words dependent on BAR is empty
: t1 foo ;
: t2 foo bar ;
s" foo" show-deps \ shows T1 and T2 are dependent on FOO
s" bar" show-deps \ shows T2 is dependent on BAR
[THEN]