One of the many blunders of Elizabeth Rather is in section
3.2.3.2:
-------------------------------------------------------------------
The control-flow stack may, but need not, physically exist in an
implementation. If it does exist, it may be, but need not be, implemented
using the data stack. The format of the control-flow stack is
implementation defined. Since the control-flow stack may be implemented
using the data stack, items placed on the data stack are unavailable to a
program after items are placed on the control-flow stack and remain
unavailable until the control-flow stack items are removed.
-------------------------------------------------------------------
What happened here is that some of the ANS-Forth committee members wanted the control-flow stack to be distinct from the data-stack because this is obviously a good idea. Forth Inc. uses the data-stack for control-flow data however (Elizabeth Rather has described this as being "convenient"). So, the solution as always, was ambiguity. She just said that either behavior would be standard. As a practical matter, what this means is that Forth Inc.'s idiotic method becomes the standard. Everybody has to assume that the control-flow stack is the data-stack, because otherwise their code won't work under SwiftForth and they will get blamed for writing a non-standard program.
When meta-compiling, it is necessary to put your data somewhere. The obvious place would be the data-stack. This can't be done however, because the control-flow data (generated by IF BEGIN etc.) is on the data-stack getting in the way of you accessing your own data. So, you need to put your data somewhere else. The two choices are the return-stack and locals. The return-stack can be used (Bernd Paysan has posted code on comp.lang.forth that uses the return-stack), but this only works when you have very little data. Locals work a lot better.
Here is an example:
----------------------------------------------------------------------------
true value bounds-check?
\ Use TO to set BOUNDS-CHECK? to FALSE when you are ready for your production version.
: check1 ( x1 dim1 -- x1 ) over u> not abort" *** array index 1 out of bounds ***" ;
: check2 ( x2 dim2 -- x2 ) over u> not abort" *** array index 2 out of bounds ***" ;
: check3 ( x3 dim3 -- x3 ) over u> not abort" *** array index 3 out of bounds ***" ;
: check4 ( x4 dim4 -- x4 ) over u> not abort" *** array index 4 out of bounds ***" ;
: check5 ( x5 dim4 -- x5 ) over u> not abort" *** array index 5 out of bounds ***" ;
: check6 ( x6 dim4 -- x6 ) over u> not abort" *** array index 6 out of bounds ***" ;
: <check1> ( dim1 -- ) bounds-check? if lit, postpone check1 else drop then ;
: <check2> ( dim2 -- ) bounds-check? if lit, postpone check2 else drop then ;
: <check3> ( dim3 -- ) bounds-check? if lit, postpone check3 else drop then ;
: <check4> ( dim4 -- ) bounds-check? if lit, postpone check4 else drop then ;
: <check5> ( dim4 -- ) bounds-check? if lit, postpone check5 else drop then ;
: <check6> ( dim4 -- ) bounds-check? if lit, postpone check6 else drop then ;
: <3array> { dim1 dim2 dim3 siz1 name | adr siz siz2 siz3 -- } \ 3-dimensional array
dim1 siz1 * to siz2 dim2 siz2 * to siz3 dim3 siz3 * to siz
align here to adr siz allot
name get-current :name \ runtime: x1 x2 x3 -- element-adr
dim3 <check3>
siz3 lit*, swap, \ runtime: x1 x3*s3 x2
dim2 <check2>
siz2 lit*, +, swap, \ runtime: x3*s3+x2*s2 x1
dim1 <check1>
siz1 lit*, +, adr lit+, ;, \ runtime: x3*s3+x2*s2+x1*s1+adr
c" ^" name get-current :2name \ runtime: -- adr
adr lit, ;,
c" lim-" name get-current :2name \ runtime: -- adr-past
adr siz + lit, ;,
name c" -zero" get-current :2name \ runtime: --
adr lit, siz lit, s" erase ; " evaluate
name c" -size" get-current :2name \ runtime: -- siz1
siz1 lit, ;,
name c" -dim" get-current :2name \ runtime: -- dim1 dim2 dim3
dim1 lit, dim2 lit, dim3 lit, ;,
;
: 3array ( dim1 dim2 dim3 size -- ) bl word hstr dup >r <3array> r> dealloc ;
----------------------------------------------------------------------------
You said:
"I've not implemented locals in kForth, nor do I feel any compulsion to do so."
This tells me that you have never written any meta-compiling words. How else do you work around Elizabeth Rather's idiotic rule that control-flow data may be on the data-stack getting in your way?