From: pazsan@Informatik.TU-Muenchen.DE (Bernd Paysan)
Subject: Re: locals (was: Floating Point)
Originator: pazsan@hphalle4b.informatik.tu-muenchen.de
Organization: Technische Universitaet Muenchen, Germany
Date: Fri, 16 Oct 1992 15:23:40 GMT


In article <1992Oct15.141124.2771@email.tuwien.ac.at>, anton@mips.complang.tuwien.ac.at (Anton Martin Ertl) writes:
|> In article <1992Oct5.165349.16826@Informatik.TU-Muenchen.DE>,
|> pazsan@Informatik.TU-Muenchen.DE (Bernd Paysan) writes:
|> |> 
|> |> In article <1992Sep28.070230.13446@email.tuwien.ac.at>,
|> anton@mips.complang.tuwien.ac.at (Anton Martin Ertl) writes:
|> |> |> I have spotted one problem with locals: They cannot be postponed, and
|> |> |> they are incompatible with the current model of postponing (dictionary
|> |> 								^^^^^^^^^
|> |> |> lookup at postpone time). This may look like a purists complaint, but
|> |>    ^^^^^^^^^^^^^^^^^^^^^^^^
|> |> |> such incompatibilities tend to cause problems when you want them
|> |> |> least.
|> |> |> 
|> |> It should be: "dictionary lookup at postpone's execution time"; and since
|> |> POSTPONE must be immediate, this is the compile time.
|> 
|> This is the compile time of the word containing the POSTPONE. But with
|> respect to the postponed word, it's compile-compile time, which I
|> chose to call postpone time. I.e. at postpone time the word is
|> postponed; when the word containing the postpone is executed, the word
|> is compiled (compile-time); and finally the word may be executed
|> (run-time).
|> 
Exactly

|> |> Another question: Where do
|> |> you want locals POSTPONEd to (say compiled instead of postponed, it is the right
|> |> word)? A local is local to the definition where it appears (thus it is called
|> |> "local"). It doesn't exist in other definitions. Compiling or postponing is
|> |> adding code to other definitions. Example:
|> |> 
|> |> : LOCALCOMPILER  ( anything -- )  LOCAL A
|> |>   POSTPONE A ; IMMEDIATE
|> |> 
|> |> : LOCALUSER ( a b -- ) { A B -- } \ another local syntax
|> |>   LOCALCOMPILER B + ;
|> |> 
|> |> What do you expect LOCALUSER will do? :-)
|> 
|> Well, I expect POSTPONE to complain or LOCALCOMPILER or LOCALUSER to
|> crash or behave unpredictably. That's what I mean with "the concepts
|> are incompatible": I can think of no way to combine locals and
|> POSTPONE.
|> 
Let me try to explain, what my implementation of Locals will do:

My locals are immediate, because they try to access the return stack with an
index depending on how many other locals are defined later. So A's compile time
code is added to LOCALCOMPILER. Since locals are defined in a temporary area
and forgotten after the scope ended, this code is to be override by the next
local (A from LOCALUSER). Now we are happy: The string size of 'A' is both the
same, so the code gets to the same position. Both are the first locals in the
word, so their index into the local stack frame is the same. This example will
(surprisingly) do exactly what we wanted: LOCALUSER will execute A B + :-).

|> Let me explain one application I am thinking of:
|> 
|> Gray (a parser generator written in Forth) has rules of the form:
|> 
|> (( factor (( "*" factor {{ * }}
|>           || "/" factor {{ / }}
|>           )) **
|> )) <- term ( -- n )
|> 
|> where the things in curly brackets are actions written in Forth.
|> Currently Gray works as follows: "((", "{{", "**", etc are Forth words
|> that build a data structure. "{{" builds an anonymous word (with
|> ":NONAME"), and "}}" terminates this, similar to ";". Later, Gray
|> builds an executable parser as collection of Forth words; The
|> anonymous words are "COMPILE,"d into the parser.
|> 
|> Now it would be nice to extend Gray with variables local to the
|> *rule*. This can be done by remembering the code between curly
|> brackets as *string*; later (at parser generation time) the strings
|> are "EVALUATE"d in compile mode. There's one problem with this: The
|> "EVALUATE" will happen in a different environment (dictionary
|> contents, search order) than the old scheme, so code may break, if I
|> make this change. Apart from that, it bugs me that I cannot use the
|> skalpels that are especially designed for such jobs ("COMPILE," or
|> POSTPONE), but have to use a butcher's knife like "EVALUATE".
|> 
|> Why do I feel that way about "EVALUATE": "EVALUATE" uses the
|> dictionary ("POSTPONE" does not need it at compile time). What it
|> does, depends on a lot of things that are hard or impossible to
|> control: The search order and the words defined in the dictionary
|> (among them redefined words). Under some circumstances I can control
|> this; in these cases "EVALUTE" is ok. But if I use it in a word
|> accessible to others (e.g. in the parser generator, or in a library),
|> this word inherits "EVALUATE"s problems and I have to warn the users
|> about it. Eventually this will cause a lot of pollution of the Forth
|> environment. So: "EVALUATE" is incompatible with modular programming.
|> 
|> |> |> Apart from that, locals look fine (but not the Basis 15 locals
|> |> |> wordset). But who knows what other evils they hide behind their back?-)
|> |> |> 
|> |> We have LOCAL| last to first | now, that takes ( first to last -- ).
|> |> And you can
|> |> define anything like TILE's syntax with (LOCAL).
|> 
|> I meant the restrictions on LOCALs usage.
|> 
They are due to the implementation on the return stack (and the scope
limitation of locals).

|> I did not know about the "last to first" syntax, but I find it
|> horrible. One of the few things where the opinions of the Forth
|> community don't differ is stack comments. Now what's more natural than
|> to write locals in the same order? All the locals schemes I know
|> (Tevets, Glass' and Patels (TILE)) use this order.
|> 
|> Writing it the other way round is error-prone and harder to read. I
|> guess the rationale for this is that it saves the vendors half an hour
|> in the implementation. But it will cost its users much more. Yes, I
|> know I can do something different with (LOCAL), but I may have to read
|> other peoples code and I really would prefer a standard that I can
|> use.
|> 
Half a minute. Some time ago someone showed, that the only thing you have to do
to get locals in the right order is to save >IN until you get the end mark and
the process the stacked up words.

Even simpler: If you have only one local defining section (no multiple scopes,
and no LOCAL A <any code> LOCAL B), as it is restricted in dpANS, you only have
to care that locals get in reverse, and the first local name accesses the last
moved value (it's really the simplest solution - but incompatible with
(LOCAL) and dpANS!).

Coding example: Given is the primitive LPICK, that takes a number compiled
behind it. LPICK may look like

: LPICK  R> DUP @ CELLS RP@ + @ SWAP >R ;

>L puts n locals (number following the token of >L) to the local stack (in
reverse order, i.e. by processing n times >R).

LDROP (also taking a number from the next position) removes n locals.

: LDROP  R> DUP @ CELLS RP@ + RP! >R ;

<TEMP and TEMP> open and close a temporary buffer for the local headers, that
is reset at the end of local's scope.

VARIABLE LOCAL#
: (LOCAL:  CREATE  LOCAL# @ ,  1 LOCAL# +! IMMEDIATE
  DOES>  COMPILE LPICK @ , ;			\ right order or
  DOES>  COMPILE LPICK @ LOCAL# @ 1- SWAP - , ;	\ "left" order

: { ( "local" .. "local" <<}>> -- )  <TEMP LOCAL# OFF
  BEGIN  >IN @  BL WORD COUNT S" }" COMPARE  WHILE
         >IN !  (LOCAL:  REPEAT
  TEMP>  COMPILE >L LOCAL# @ , ; IMMEDIATE

If >L keeps the order of the local numbers, "left" order must be used in
(LOCAL:.

|> Hmm, looking into BASIS 15, section B.17, I see two examples of doing
|> it the "last to first" way and none doing it the right (8-) way. A
|> proposal to the ANSI TC: I will try to implement a right way locals
|> syntax (with "(LOCAL)"), if you promise me to put it in that section.
|> 
|> - anton
|> -- 
|> M. Anton Ertl                    Some things have to be seen to be believed
|> anton@mips.complang.tuwien.ac.at Most things have to be believed to be seen

-- 
Bernd Paysan
"Keep it stupid simple!"