6.17.5.4 Defining translators

A translator is a table of three actions: interpretation, compilation, and postponing. You should design the translator and its actions like the system-defined translators, with additional data, maybe some parsing, and at least an interpreting run-time (and in the normal case let the compiling run-time and postponing run-time follow from that, see Define recognizers with existing translators). You then have to define the action words to implement the sequence: consume the additional data, possibly scan, then perform the run-time appropriate for the action.

You define a translator with

translate: ( int-xt comp-xt post-xt "name" –  ) gforth-experimental “translate-colon”

To make this a little more concrete, here is an implementation for translate-cell:

' noop                       ( x -- x )                             \ int-xt
' lit,                       ( compilation: x -- ; run-time: -- x ) \ comp-xt
:noname lit, postpone lit, ; ( postponing: x -- ;  run-time: -- x ) \ post-xt
translate: translate-cell

If a recognizer for a single-cell literal (e.g., rec-tick) matches the input string, it pushes the value x of the literal (the xt of the ticked word in case of rec-tick) on the data stack and the xt of translate-cell. When the interpretation semantics is needed, int-xt is executed, and x stays on the stack. For the compilation semantics, x is compiled into the current definition as literal.

For postponing, more time levels are involved: at text-interpretation time (when the recognizer runs and the translator action is performed) the current definition is d1. When d1 runs, the current definition is d227. The post-xt of the translate-cell implementation above first compiles x into d1 and also compiles lit, into d1 (that’s the postpone lit, part). When d1 runs, it pushes x and then the lit, compiles x into d2.

Many literal translators follow this scheme.

A translator that is quite different is translate-name. Here’s an implementation:

: name-intsem ( ... nt -- ... )
  name>interpret execute-exit ;
: name-compsem ( ... nt -- ... )
  name>compile execute-exit ;
: name-compcompsem ( nt -- )
  lit, postpone name-compsem ;
' name-intsem ' name-compsem ' name-compcompsem translate: translate-name

Name-intsem performs the interpretation semantics of nt, by getting the xt of the interpretation semantics and executing it. Here execute-exit is used, in order for return-stack words to work (that’s a Gforth 1.0 feature). Also, in Gforth 1.0 all words have interpretation semantics, so the result of name-interpret is not tested for 0.

Name-compsem performs the compilation semantics of nt.

Name-compcompsem compiles the compilation semantics of nt. This is achieved by compiling nt and name-compsem into the current definition d1. When d1 runs, the result performs the compilation semantics of nt at that time.


Footnotes

(27)

If there is no current definition when something is compiled, Gforth outputs a warning.