[comp.lang.forth] FORTH Modules: current confusion?

keith@curry.uchicago.edu (Keith Waclena) (12/14/89)

Some background: It's the end of the quarter and I'm about to slip a
little FORTH into a reading course I'm teaching on data encapsulation
in programming languages.  The course has followed a historical
progression from block structure through modules, abstract data types
and finally object-oriented programming.  We read a paper by Friedman
and Felleisen[1] detailing how one can add modules to Scheme with a
page or so of relatively portable code.  Now I thought I'd give my
students a one-page paper by Schorre[2] on how to add modules to FORTH
in 3 short lines of code.

My problem is this: Schorre's code is (I think) fig-FORTH and needs to
be updated to FORTH-83 for the systems I have around.  Here is
Schorre's complete code:

	: internal   current @ @ ;
	: external   here ;
	: module     pfa lfa ! ;

I think I understand how this is intended to work, and here's my
translation to FORTH-83 (using Harris's proposed words for definition
field address conversion):

	: internal   current @ @ ;
	: external   here ;
	: module     n>link ! ;

My problem is that, while Harris's words seem to be a de facto
standard (all my systems have them), this code only works on one
system: Laboratory Microsystems PC/FORTH.  It fails to work under F83
and F83S, and also under F-PC (version 2.something).

Here's an example of the use of these words, to create a global
variable that's private to three routines that use it for
communication:

	internal
	   variable foo
	external
	   : reset   0 foo ! ;
	   : inc     1 foo +! ;
	   : hmm     foo @ . ;
	module

The idea is that foo is only visible to the three words after
external, because module has adjusted the dictionary links to jump
over foo.  And sure enough, under PC/FORTH, the three words can find
foo, though it doesn't show up in the dictionary anymore.

In F83 and F83S, however, the three words can find foo, but it never
vanishes from the dictionary!  Exactly the same thing occurs with
F-PC.  Strangely enough, the system doesn't crash, even though I don't
know where I'm storing that address...

Can anyone tell me what the difference is between these systems that
explains this?  I realize that this sort of dictionary manipulation
isn't really in line with the 83 standard (which I think is too bad),
but I didn't think I'd have this much trouble with such a simple idea.
My two guesses as to where my problem lies are as follows: lack of
understanding of current (what exactly *does* it point to, anyway?
This is not at all clear from the standard document.), or perhaps a
problem with hashed dictionaries?

Thanks in advance,

						Keith

References:

Felleisen, M. and D. P. Friedman.  1986.  ``A Closer Look at Export
and Import Statements''.  *Computer Languages* (11), pp. 29-37.

Schorre, Dewey Val.  1980.  ``Adding Modules to Forth''.  *Proceedings
of the 1980 FORML Conference*, p. 71.


--
Keith WACLENA                             keith@curry.uchicago.edu
CILS / TIRA / U of Chicago                keith%curry@uchimvs1.bitnet
1100 E.57th.St Chi IL 60637 USA           ...!uunet!curry.uchicago.edu!keith

wmb@SUN.COM (12/14/89)

> : internal   current @ @ ;
> : external   here ;
> : module     n>link ! ;
>
> ... [doesn't work in F83] ...

because the F83 dictionary is multiply-threaded.  Instead of a single
linked list, a vocabulary is #THREADS (usually 4) linked lists.  The
thread to search when looking for a word is determined by a hash function,
which happens to be the lower n bits of the first character in the name.

It also fails because the "here" in external is assumed to point to the
name field address of the next word defined after "external".  In systems
where the name field is indeed the first thing in a word, this is okay.
However, in F83, both the "view" field and the link field precede the
name field.

In order to implement the module function in F83, you will need to
do the following (assuming that you don't change the current
vocabulary in the process).

 : internal   ( -- hidden-start-address )  here  ;
 : external   ( -- hidden-end-address )    here  ;
 : module     ( start end -- )
     current @  #threads 2*  bounds  do
        2dup  i  remove
     2 +loop
 ;

Where REMOVE works as follows:

 remove  ( start-adr end-adr list-head -- )
  Traverse the linked list, removing entries between
  start and end.

: remove  ( start-adr end-adr list-head -- )
   \ Find node just above "end"

   swap >r                                 ( start-adr list-head ) ( r: end )
   begin  dup @  r@ >  while  @  repeat    ( start-adr node' )
   r> drop                                 ( start-adr node' )

   \ Find node just below "start"

   swap >r  dup                            ( node' node' )  ( r: start-adr )
   begin  @  dup  r@ <  until              ( node' node'' )
   r> drop                                 ( node' node'' )

   swap !                                  ( )
;

Warning:  the preceding code has not been tested.  If it has bugs,
finding them is left to the reader as an exercise.


I don't know about F-PC.  I suspect that it works similarly to F-83.


Another solution strategy would be to use the vocabulary search mechanism,
something like this:

 vocabulary temporary
 : internal  ( -- adr )  also temporary definitions  here  ;
 : external  ( -- )
    previous  context @  temporary also  context !  definitions
 ;
 : module  ( adr -- )
    context @  previous         ( old-context )
    context @  swap  context !  ( temporary-adr )
    trim
 ;

This depends on the existence of the F83 word:
 TRIM  ( adr voc-adr -- )
  Unlinks all words defined after "adr" in the vocabulary
  "voc-adr"

Mitch

ir230@sdcc6.ucsd.edu (john wavrik) (12/15/89)

Keith Waclena writes:

#  My problem is this: Schorre's code is (I think) fig-FORTH and needs to
#  be updated to FORTH-83 for the systems I have around.  Here is
#  Schorre's complete code:
#
#          : internal   current @ @ ;
#          : external   here ;
#          : module     pfa lfa ! ;

#  My two guesses as to where my problem lies are as follows: lack of
#  understanding of current (what exactly *does* it point to, anyway?
#  This is not at all clear from the standard document.), or perhaps a
#  problem with hashed dictionaries?

    Your analysis is correct. After 1983 the dictionary was no longer required 
to be a simple linked list. Systems like F83 elected to increase compilation 
speed by putting names in one of several linked lists ("threads") using a 
hashing scheme -- the number of threads usually varies from 4 (in F83) to 512 
(in a version of Forth written by Guy Kelly -- the chairman of the 1983 
Standards Team) and varies from system to system, as does the hashing 
function. The Guiness Book of Records lists Bjork Fjorn of Norway as the 
programmer with the most threads in his version of Forth -- 1,203,456. (Bjork 
admits that he does not use vocabularies very often.) 

   The link field now only refers to the previous word IN A GIVEN THREAD (so 
God only knows what you relinked!). 

   There are also some other even more subtle problems in adapting the code.
In figForth,

: INTERNAL  CURRENT @ @ ;
       would have given the name field address of the most recent entry in the 
       current vocabulary 

: EXTERNAL  HERE ;
       would have given the address of name field of the next word to be 
       defined.

: MODULE  PFA LFA !  ;
       would have set the link field of the first external entry to point
       to the entry before the first internal entry.

In F83 the link fields point to the link field of the previous entry in the
same thread -- but there is a view field that comes before the link field.
So the definition of EXTERNAL would need modification even if the dictionary
were a simple linked list (which it isn't).

                                    -------

   There is another simple solution to your problem: alter the name field so 
that hidden words are not found 

     : KILL   128  ' >NAME  C!  ;

KILL <name> will set the character count of the name field of <name> to 0.
You can kill anything you want never to be found in a dictionary search 
(relinking the dictionary has the same effect). Note: this is not 
portable and violates the Forth-83 Standards, but it does work on F83. (You 
can also use a mechanism like that found in the definition of WORDS to 
obliterate all names between two addresses.) 

                                    -------

   What you are supposed to do these days is to handle all dictionary 
manipulation by vocabularies (rather than manipulating dictionary links 
directly). Each time a new local environment is created, the variables (and 
words) local to that environment are to be put in a vocabulary. In F83 your 
example can be handled like this: 

1.   VOCABULARY TEMP   TEMP ALSO DEFINITIONS    \  internal            
        VARIABLE FOO

2.   FORTH DEFINITIONS                          \  external
        : RESET  0 FOO ! ;
        : INC    1 FOO +!  ;
        : HMM    FOO ? ;

3.   PREVIOUS FORTH DEFINITIONS                 \  module

In step 1, a new vocabulary called TEMP is installed and placed in the
search order.  The variable FOO is put in this vocabulary.

In step 2, the FORTH vocabulary is put on top of TEMP in the search order
and is also made the current vocabulary for the new definitions.

In step 3 the TEMP vocabulary is eliminated from the search order.

NOTES:
1.  The words used cannot be easily simplified. In particular
         : INSTALL   VOCABULARY TEMP  TEMP ALSO DEFINITIONS ;
    cannot be used to create the new vocabulary, since "TEMP" is not
    in the dictionary.

2.  During stage 2, the FORTH dictionary occurs in the search order before
    TEMP -- thus if FORTH has a word "foo" it will be used rather than the
    word in TEMP. This is one of the major disadvantages of this method.

3.  The vocabulary mechanisms used above were part of a proposal to
    the 1983 Standards. They are included in F83 but are not part of the 
    Standard. 

4.  The example assumes the FORTH vocabulary but can be easily modified
    to apply to any current vocabulary.

If you are willing to accept tampering with the linking of a particular 
version of Forth then very powerful things can still be done -- but not 
portably and not as simply.


                                                  John J Wavrik 
             jjwavrik@ucsd.edu                    Dept of Math  C-012 
                                                  Univ of Calif - San Diego 
                                                  La Jolla, CA  92093 

jax@well.UUCP (Jack J. Woehr) (12/17/89)

	The problem with CURRENT @ @ is that in F83 and F83S
it will get you one particular thread of the four threads
in the vocabulary which is CURRENT.

	Further, in F83S and FPC the dictionary headers are
in a separate segment from the address lists and you have
to use extended memory operators to reach them.  "!" won't
reach them.

{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{} jax@well     ." Sysop, Realtime Control and Forth Board"      FIG      {}
{} jax@chariot  ." (303) 278-0364 3/12/2400 8-n-1 24 hrs."     Chapter    {}
{} JAX on GEnie       ." Tell them JAX sent you!"             Coordinator {}
{} jax@well.sf.ca.us                                                      {}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}

stever@tree.uucp (Steve Rudek) (12/19/89)

In article <15058@well.UUCP>, jax@well.UUCP (Jack J. Woehr) writes:
> 	Further, in F83S and FPC the dictionary headers are
                ^^^^
What is this?  That is, how does it differ from plain "F83".  Does anyone 
know if F83 is a "tiny" model program with code and data intermixed in the
same segment?  I know it is a "com" file but it is my understanding that
a com program may be "small" and not "tiny".  The reason I ask is it pertains
to my interest in porting F83 to Xenix 386.  I'm wondering if I could just
replace the DOS calls with Xenix system calls and then change the metacompiler
to spit out a hex listing of everything over "100 hex".  Then I could
transport that file to xenix and relatively easily prepend a header...and it
might work...?
-- 
{pacbell!sactoh0! OR ucdavis!csusac!}tree!stever

john@aplcen.apl.jhu.edu (John Hayes) (12/21/89)

In article <6708@tank.uchicago.edu> keith@curry.uchicago.edu (Keith Waclena) writes:
>Some background: It's the end of the quarter and I'm about to slip a
>little FORTH into a reading course I'm teaching on data encapsulation
>in programming languages.  The course has followed a historical
>progression from block structure through modules, abstract data types
>and finally object-oriented programming.  We read a paper by Friedman
>and Felleisen[1] detailing how one can add modules to Scheme with a
>page or so of relatively portable code.  Now I thought I'd give my
>students a one-page paper by Schorre[2] on how to add modules to FORTH
>in 3 short lines of code.

	Here is a module syntax I have been experimenting with:

module> module's-name
   ( hidden / private definitions goes here )
public:
   ( public definitions go here )
private:
   ( more hidden data goes here.  public: and private: may be used as
     many times as necessary or not at all. )
endmodule>

module> ... endmodule> encloses a module definition.  By default, definitions
that occur within the module can not be found outside the module.  Definitions
made after use of the public: pseudo-label can be found outside the module.
private: switches the compiler back to hiding definitions.

	I have provided two implementations.  The first implementation is
meant to be portable.  It does not rely on dictionary structure but you
must have also and previous.

	The second implementation is written is in ANS Forth.  Of course,
there is no such thing as ANS Forth yet; the October, 1989 Basis was used.
The code exploits a controversial feature of ANS Forth.  In ANS Forth, : no
longer has any effect on search order (i.e. no current @ context ! ).  In
my opinion this a cleaner factoring and simplifies some programs, as
demonstrated by the two implementations of module>.  This change to :
is controversial because it changes the way some people use their Forth
systems.

	The purpose of this posting is twofold:  to describe an interesting
modularization mechanism and to spark discussion on the new : .  Any comments?

-------------------cut here---------------------------------------------
\ (c) 1989 Johns Hopkins University / Applied Physics Laboratory
\ Modules - Create a local name space. Each definition in a module may
\ be declared to be visible (i.e. findable) outside the module or only
\ visible within the module.

\ Usage syntax:
\ module> module's-name
\   ( hidden / private definitions goes here )
\ public:
\   ( public definitions go here )
\ private:
\   ( more hidden data goes here.  public: and private: may be used as
\     many times as necessary or not at all. )
\ endmodule>

variable public?

: module>	\ ( --- ) Start a module definition.  Subsequent word
		\ definitions will be hidden.
   >in @ vocabulary >in !		\ module is really a vocabulary
   0 public? !				\ private definitions by default
   ' also execute definitions ;		\ module is compilation and search

: swap-vocabs	\ ( --- ) Exchange the first two vocabularies in the search
		\ order.
   context @ previous context @
   swap context ! also context ! ;

: public:	\ ( --- ) Subsequent definitions will be visible outside module.
   public? @ 0= if swap-vocabs definitions 1 public? ! then ;

: private:	\ ( --- ) Subsequent definitions will be hidden.
   public? @    if swap-vocabs definitions 0 public? ! then ;

: endmodule>	\ ( --- ) End a module definition.  Restore vocabulary
		\ environment.
   private: previous definitions ;

-------------------cut here---------------------------------------------

\ (c) 1989 Johns Hopkins University / Applied Physics Laboratory
\ Modules - Create a local name space. Each definition in a module may
\ be declared to be visible (i.e. findable) outside the module or only
\ visible within the module.

\ Usage syntax:
\ module> module's-name
\   ( hidden / private definitions goes here )
\ public:
\   ( public definitions go here )
\ private:
\   ( more hidden data goes here.  public: and private: may be used as
\     many times as necessary or not at all. )
\ endmodule>

\ Implementation note: for this code to be useful, : cannot change search order.

: module>	\ ( --- ) Start a module definition.  Subsequent word
		\ definitions will be hidden.
   >in @ vocabulary >in !		\ module is really a vocabulary
   ' also execute definitions ;		\ module is compilation and search

: public:	\ ( --- ) Subsequent definitions will be visible outside module.
   context @ previous definitions 	\ definitions into outside vocabulary
   also context ! ;

: private:	\ ( --- ) Subsequent definitions will be hidden.
   definitions ;			\ sugar

: endmodule>	\ ( --- ) End a module definition.  Restore vocabulary
		\ environment.
   previous definitions ;
-------------------cut here---------------------------------------------

                                        John R. Hayes
                                        Applied Physics Laboratory
                                        Johns Hopkins University
					john@aplcen.apl.jhu.edu

jax@well.UUCP (Jack J. Woehr) (12/21/89)

	F83S is Wil Baden &al upgrade to F83. It is syntactically
almost the same as F83. Functionally, it is greatly improved, including
the best screen file editor that was then ( 1986) available. It is
"cousin" to Wil's F83X for the Apple.

	F83S puts the headers in a separate segment, where they get
out of the way of the dictionary and allow themselves to be discarded
for turnkey applications.

	F83S is in my view the most sophisticated screen-file oriented
PD Forth system for the PC. Of course, it is stylistically dated, but
still very useful to me at work.

	F83S6.ARC can be downloaded from the RealTime Control and Forth
Board, number below.

{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{} jax@well     ." Sysop, Realtime Control and Forth Board"      FIG      {}
{} jax@chariot  ." (303) 278-0364 3/12/2400 8-n-1 24 hrs."     Chapter    {}
{} JAX on GEnie       ." Tell them JAX sent you!"             Coordinator {}
{} jax@well.sf.ca.us                                                      {}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}