StateSmart Words and POSTPONE

The ANSI Standard On Forth has ensured that words are usually not state-smart, since it can be a problem when trying to postpone execution in self-constructed compiling words. Only two compile-only words exist that have an extra execution-semantics, one is s-quote (for use with included, the other is to. A note in the standard says (near TO, dpans13#13.6.1.2295 )

Note:

An ambiguous condition exists if either POSTPONE or [COMPILE] is applied to TO.

This note can be seen as a big red warning for anything that is state-smart - state-smart words are one of the widely used implementation tactics to make life easier for the usage of words. It is escpially a bit cumbersone while learning the forth language. In general, a forth user can test a little series of words on the command line in interpret mode, and when the things work as expected, just surround it with ":" and ";" to memorize the word-sequence for further reference. It makes one of the strengths of forth that one can easily factor out command-sequences and attach a nice and readable name to it.

The ANS Forth describes a few pairs of words to handle the problems with postpone - one is an immediate compile-only word, the other is just the execution that is done by that word before compiling it into the dictionary - usually to leave a value on the stack. The words are:

`char` and `[char]`

` [char] ` is compile-only - it will get the (ascii-) value of the next char, and compile it as a `literal`. It's interpret-semantics are undefined, and the word `char` must be used outside of your colon-definitions. The `char` word is more or less the implementation used by `[char]`, as in

 : [char]  ?comp char postpone literal ; immediate 

In pfe, the `[char]` is state-smart - in interpret-mode, it will only do `char` and it will not call `literal`. The char-value is left on the stack just as it is done in a compiled word that has used `[char]`.

 : [char]  char state @ if literal then ; immediate 

`'` and `[']` (tick and bracket-tick)

` ['] ` is compile-only - it will get the execution-token of the next word, and compile it as a `literal`. It's interpret-semantics are undefined, and the word `'` must be used outside of your colon-definitions. The `'` word is more or less the implementation used by `[']`, as in

 : [']  ?comp ' postpone literal ; immediate 

In pfe, the `[']` is state-smart - in interpret-mode, it will only do `'` and it will not call `literal`. The tick-value is left on the stack just as it is done in a compiled word that has used `[']`.

 : [']  ' state @ if postpone literal then ; immediate 

`."` and `.(` and `type`

` ." string" ` is compile-only - it will parse the string, compile it, and when the compiled word is executed, it will print the string to the terminal. The usage of ` .( string) ` will run immediatly, to show the string to the terminal in both compile- or interpret-mode, which is good for notifications during compiling of a forth script. The non-immediate word would be `type` that needs to be passed a string which could be compiled with `sliteral`.

In PFE, the `."` is made state-smart, therefore in interpret-mode, it will instantly print the string to the terminal, just like `.(` would do. In compile-mode it parses and compiles the string (`sliteral`) and postpones a `type`-execution.

 
	: .( 	postpone "  type ; immediate
	: ."  	postpone " 
		state @ 0= if type 
		else postpone sliteral postpone type fi
	; immediate

`C"` and `S"` vs `sliteral` and (nonstandard) `parse,`

` C" string" ` is compile-only - it will parse the string, compile it, and when the compiled word is executed, the string-address will be avaiable for further usage in the word. There is originally no interpret-semantics for the strings, but ANS Forth has defined one only for the usage with `included`. You will find that the ANS Forth standard has two descriptions of `S"`, where one is in CORE, the other is in FILE-EXT - only the latter is more or less state-smart.

The problem with interpreted string constants is the question where the string is stored. In traditional systems, the stringconstant is put into a temporary location called the `pocket`. Many systems (including the PFE) have more than one pocket that are used in a round-robin fashion, but the user should be aware that interpret string-constants are only temporary - they will be overwritten in the pocket by some other call later on.

The usage of `included` from the FILE-EXT wordset however suggests that one does need stringconstants in interpret-mode, and ANS Forth has therefore defined that `S"` should be extended with an interpret-semantics if `included` is available in a forth system. However, `S"` is easier for temporary strings than `C"` - an implementation can choose to return the address and length of the charstring in the TIB - the terminal input buffer. In such a system, the use of such an intepret-mode string construct would only last for a single line entered - the following `included` call must be on the same line as the `S"`-quoted string-constant.

PFE however is very traditional (it's one of the features of PFE) and in interpret-mode, all these stringconst quote-words will actually parse the string into a pocket whose address is returned. Usually, PFE is configured to have eight pockets, and a maintainer is asked to never configure with less than two pockets to enable move-file and rename-file operations from the commandline. And always remember - interpret-mode stringconstants are temporary, and their number is limited.

( To postpone these words can again be a problem, just as it is with state-smart words. Be sure to use `sliteral` to add a string-constant to a meta-compiled definition, and look into the documentation of the nonstandard word `parse,` to add just the chars of the stringconstant to the dictionary. )
`literal` and `fliteral` and `2literal` and `sliteral`

All these words are compile-only - they are used to compile a value on the (cs-)stack into the dictionary and to return their value/address during execution of the compiled word.

It is easy to add a bit of state-smartness to these words - compilation is only done in compile-mode, while in interpret-mode it will do as if it is already running. `literal` will leave the value on stack, actually a `noop` in pfe. The same for `2literal` that leaves the 2value on stack, and for `fliteral` and the f-stack. `sliteral` will effectivly do nothing either, leaving you with the pocket-string. In compile-mode, it would `allot` and copy the string to the defined word leave that address later.

If you are interested about the whole topic of postpone, state-smart words and ANS Forth descriptions with differing compile-mode and interpret-mode semantics ("combined words"), then have a look at gforth which uses a truly different approach about compile-only/interpret-only/combined/self-parsing and other immediate/non-immediate words.

Anton Ertl (the gforth author) has some more indepth documentation about the topic availabl on the Vienna university server, see

also, there was a discussion about this topic on comp.lang.forth during 6.March.2001 to 7.March.2001, that may give you some hints

As far as I can see, state-smart implementations of the string-contant words and literal-words are very very common in the forth systems around, the state-smart variants of char/[char] and '/['] pair is not so widespread. Be sure to postpone only `char` or `'`. There is a configure-time default for PFE-compilation that can make all these statesmart words non-smart - if these compile-only words are interpeted on the command-line then a `?comp` exception is thrown - something like "trying to execute a compile-only word". The compile-default for PFE is however to make them statesmart instead of compile-only-immediate.