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 {} {}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}