[comp.lang.forth] More on START:

john@aplcen.apl.jhu.edu (John Hayes) (09/07/90)

In an earlier posting, I described a word, START:, that was added
to the Core Extensions Word Set of ANS Forth at the Vancouver
meeting.  The following is the discussion section of the proposal
for START:; it offers further motivation for standardizing START:.

I frequently want to compile Forth code fragments (code without a
head), save the code in a data structure, and later extract it for
execution.  Here is a real world example:  The Experiment Computer, a
part of Spacelab (a module that can be flown on the Space Shuttle),
sends commands to experiments in the shuttle's payload bay as a packet
containing a two digit command number.  In the Hopkins Ultraviolet
Telescope experiment we process these commands using this syntax:

	 0  CMD:     ...   code for command 0    ...     ;CMD
	 1  CMD:     ...   code for command 1    ...     ;CMD

	99  CMD:     ...   code for command 99   ...     ;CMD

We chose this syntax because we didn't want to strain our brains
inventing 100 names and we didn't want to expend dictionary space
storing names that would never be used.  The nth command is executed
with DOCMD which takes n as a stack argument.

The problem described above is a specific instance of the general
problem of constructing headerless code fragments.  Attempting to
implement CMD:, etc. will reveal whether we can solve the general
problem.  An implementation that works on many systems is:

	CREATE CMD-TABLE  100 CELLS ALLOT
	: CMD:   ( N -- ) HERE SWAP CELLS CMD-TABLE + ! ] ;
	: DOCMD  ( N -- ) CELLS CMD-TABLE + @ >R ;

This implementation has several problems.  In CMD: using HERE to find
the address of the subsequently compiled code is non-portable; some
systems separate code and data and HERE points to data.  In DOCMD
pushing the address of the code on the return stack and returning isn't
guaranteed to work; some systems do not use the return stack for return
addresses and some systems use a return address bigger than one cell.
Despite there problems, this is the most portable solution I am able to
find.

What we really need is to construct an execution token in CMD: and pass
this token to EXECUTE in DOCMD.  Unfortunately, there is no standard
way to construct an execution token except through :.  That's where
START: comes in.  START: creates an execution token such that code
subsequently compiled into the dictionary will be associated with the
execution token.  START: returns the execution token on the stack.

With START: the definitions of CMD: and DOCMD become:

	: CMD:   ( N -- ) START: SWAP CELLS CMD-TABLE + ! ] ;
	: DOCMD  ( N -- ) CELLS CMD-TABLE + @ EXECUTE ;

START: is a general solution to the problem of creating headless code
fragments.  One of Forth's great strengths is that it allows the
programmer to create application specific languages.  The application
language is frequently a mixture of Forth code and application
constructs.  The language is implemented by storing Forth code as
fragments in a data structure.  To illustrate this, I have included
examples of four problems that require the functionality of START: to
implement portably.  The first three examples are from my own
programming experience and the last is a published example.

I have recently been working with an object-oriented programming system
implemented in Forth.  My syntax for declaring a class is:

	parent-class SUB-CLASS> class
		LOCAL: X        \ instance variables
		LOCAL: Y

		METHOD: :DOTHIS  ...   ;METHOD
		METHOD: :DOTHAT  ...   ;METHOD
	END>

METHOD: not only compiles method code, but must store the code's
execution token in a dispatch table in the class data structure.  The
dispatch table provides an efficient  way to do late message/method
binding.

A few years ago I wrote a user-extensible text editor.  The editor
provided a few, very powerful, very general editing commands and a way
to bind user-defined command to particular keystrokes.  Here are three
such commands ('d' deletes the current line, 'D' deletes to the end of
the line, and '^W' deletes the current word):

	cmd d     |<- mark scrollcursor deleterange  endcmd
	cmd D     drop mark ->| deleterange  endcmd
	cntrl W   mark ->w deleterange  endcmd

In my embedded systems programming work, I have found the following
construct useful:

	do: monitor-that-device  ... some code ...  ;do
	monitor-that-device every 5 seconds doit

Do: constructs a data structure that, among other things, contains the
execution token of the following code.  The data structure is passed to
doit, which gives the structure to a time service process.

The final example is FORPS [Matheus, C. J. "The Internals of FORPS: a
FORth-based Production System, JFAR 4/1, pp.7-27] an expert system
shell.  The syntax for declaring a rule is:

	RULE: rule-name      PRIORITY: n
	   *IF*   ... condition code ...
	   *THEN* ... action code ...
	   *END*

The data structure for each rule contains the execution tokens for the
condition code and the action code.  The condition code for every rule
is executed before deciding which rule's action code should be
executed.

In summary, Forth is at its best when designing application specific
programming languages.  This is frequently accomplished by constructing
headless code fragments.  Unfortunately, there is now no portable way
of doing this.  START: solves this problem.

                                        John R. Hayes
                                        Applied Physics Laboratory
                                        Johns Hopkins University