More Information about ThisForth
================================

TEXT INTERPRETATION
-------------------

The difference between This Forth and traditional implementations is This 
Forth's approach to input source.

This Forth sees all input as one single stream of characters.  The text 
interpreter: (1) filters strings of visible characters from this stream,
(2) recognizes them as Forth words and literals, and (3) executes the 
immediate behavior associated with each.

Pseudocode for This Forth -- error handling omitted:

	: EXPOUND	BEGIN   FILTER-EXECUTE   AGAIN ;
	
	: FILTER-EXECUTE
		GET-NEXT-WORD
		DEFINED IF
			EXECUTE-IT
		ELSE
			CONVERT-TO-NUMBER
			LITERAL
		THEN
	;

	: GET-NEXT-WORD
		SKIP-INVISIBLE-CHARACTERS   COLLECT-VISIBLE-CHARACTERS
	;

FILTER-EXECUTE is an anonymous low level Forth primitive.

Among the possible behaviors, a character string or an entire text file may 
be inserted into the input stream.  The text interpreter will not be aware 
that any such action occurred.  "PLEASE" inserts a character string, 
"STREAM" inserts a file.

In traditional implementations a source of input is specified, and then the 
text interpreter: (1) reads records one at a time into the proper input 
buffer associated with the source of input, and for each record, (2) parses 
strings of non-blank characters out of the buffer, (3) recognizes them as 
Forth words and literals, and (4) compiles or (5) executes each according 
to (6) the current compilation state and (7) an immediate flag associated 
with the word.

Pseudocode for traditional Forth -- error handling omitted:
	( Standard Forth, Section 3.4 )

	: EXPOUND	BEGIN   GET-NEXT-LINE   INTERPRET   AGAIN ;

	: INTERPRET
		BEGIN
			END-OF-LINE NOT
		WHILE
			PARSE-WORD
			DEFINED IF
				COMPILING  IMMEDIATE-FLAG 0=  AND
				IF
					COMPILE-IT
				ELSE
					EXECUTE-IT
				THEN
			ELSE
				CONVERT-TO-NUMBER
				COMPILING IF
					LITERAL
				THEN
			THEN
		REPEAT
	;

	: GET-NEXT-LINE
		SELECT-INPUT-SOURCE   READ-RECORD-INTO-BUFFER
	;

This Forth's text interpreter is not aware of the compilation state, and 
words do not have an immediate flag.  Instead each word has an immediate 
behavior which will do the right thing.

Traditional implementations are record oriented; This Forth is character 
oriented. In both, the lexical unit is a word: a string of visible 
characters.

Traditional implementations distinguish whether input is coming from 
EVALUATE, LOAD, INCLUDED, or the user input device.  This Forth does not 
make any such distinctions.  Everything comes from the user input device.

CASE OF ENDOF ENDCASE ESAC
--------------------------

The new word, ESAC, is an implementation factor of ENDCASE, discovered as I 
was pondering how to implement ENDCASE .  It is useful for its own sake -- 
more useful than ENDCASE.

ENDCASE presumes that there is a test value still on the stack.  This 
means that if you use that value between the last ENDOF and ENDCASE you 
must DUP it first, or use it and restore it (or a dummy).  

In virtually all applications I have found that you want to do something 
with it.  I recommend that in This Forth you don't use ENDCASE.  Instead 
use its definition, `DROP ESAC', to show explicitly what happened to the 
test value.  Save ENDCASE for a jump-table optimized version (some day).

The macro definitions of CASE and ESAC are specific to This Forth, but they 
can be modified to work in all systems that use the data stack as the 
control flow stack.

Standard Forth says that the control flow stack can be anywhere, but you 
must program around it as if it _were_ the data stack.  So you might as 
well use the data stack.  No more than one cell is needed for a control 
stack element, so why use more? The other stack elements are addresses, 
which by nature won't be 0.  Thus 0 can be used as a special, identifiable, 
element on the control flow stack.

The fortuitous discovery of ESAC opens the way to sweeter control flow.

Proposed revised specifications for CASE, ESAC, and OF.

CASE							CORE EXT

Compilation:    ( C: -- case-sys )

Mark the control-flow stack with an element to be used as a sentinel.

Execution:      ( -- )

Continue execution.

ESAC							CORE EXT

Compilation:    ( C: case-sys orig-1 orig-2 ... orig-n -- )

Keep resolving the control-flow stack with THEN so long as case-sys
is not on top of the control-flow stack.  Discard case-sys.

An ambiguous condition exists if THEN fails when doing this.

Execution:      ( -- )

Continue execution.

OF							CORE EXT

Compilation:    ( C: -- orig )

Put the location of a new unresolved forward reference on the control flow 
stack. Append the execution behavior given below to the current definition.
The behavior is incomplete until the forward reference is resolved, e.g., 
by THEN or ELSE.

Execution:      ( x1 x2 --   | x1 )

If the two values on the stack are not equal, discard the top value and 
continue execution at the location specified by the consumer of orig.  
Otherwise, discard both values and continue execution in line.

	OF  is equivalent to  OVER = IF DROP
		
CASE and ESAC give a solution to an inconvenience with Forth control logic.  
Suppose that despite your good intentions you have a definition with nested 
IF's and ELSE's which end with many THEN's.
  
Put CASE before the first IF, and ESAC in place of the many THEN's.

This form is clearer and it's impossible to miscount the THEN's.

Here is the sample code for Conditional Compilation.

: [ELSE]				( -- )
	1 BEGIN					( level )
		BL WORD COUNT			( level word .)
		CASE
			2DUP S" [IF]" S=
		IF
			2DROP 1+
		ELSE
			2DUP S" [ELSE]" S=
		IF
			2DROP 1- DUP ?? 1+
		ELSE
			2DUP S" [THEN]" S=
		IF
			2DROP 1-
		ELSE
			2DROP
		ESAC				( level)
		?DUP 0=
	UNTIL					( )
; IMMEDIATE

: [IF] ( flag -- ) 0= IF POSTPONE [ELSE] THEN ; IMMEDIATE

: [THEN] ( -- ) ; IMMEDIATE

Also see source for STANDARDIZE.
	
LOCAL DEFINITIONS
-----------------

This release of This Forth doesn't support local variables.  I know how 
to do it, I don't want to.  Maybe next year.

This Forth has local definitions.  Local definitions satisfy the 
objections I have to local variables.

	( Default RNG from the C Standard.  `RAND' has reasonable
	( properties, plus the advantage of being widely used. )

	| VARIABLE RANDSEED
	
	| 32767 CONSTANT MAX-RAND  ( Made local for illustration. )
	
	: RAND ( -- random )
		RANDSEED @ ( random) 1103515245 *   12345 +   DUP RANDSEED !
		16 RSHIFT   MAX-RAND AND
	;
	
	: SRAND ( n -- ) RANDSEED ! ;  1 SRAND
	
	||	( Remove names of local definitions from the dictionary. )

You can write an application with all implementation factors made local 
definitions, then disown the implementation factors so that all that 
remains known are the end user words.


