13 The optional Locals word set

13.1 Introduction

13.2 Additional terms and notation

None.

13.3 Additional usage requirements

13.3.1 Locals

A local is a data object whose execution semantics shall return its value, whose scope shall be limited to the definition in which it is declared, and whose use in a definition shall not preclude reentrancy or recursion.

13.3.2 Environmental queries

Append table 13.1 to table 3.4.

See: 3.2.6 Environmental queries.

Table 13.1: Environmental Query Strings

String Value data type Constant? Meaning

#LOCALS n yes maximum number of local variables in a definition

13.3.3 Processing locals

To support the locals word set, a system shall provide a mechanism to receive the messages defined by (LOCAL) and respond as described here.

During the compilation of a definition after : (colon), :NONAME, or DOES>, a program may begin sending local identifier messages to the system. The process shall begin when the first message is sent. The process shall end when the "last local" message is sent. The system shall keep track of the names, order, and number of identifiers contained in the complete sequence.

13.3.3.1 Compilation semantics

The system, upon receipt of a sequence of local-identifier messages, shall take the following actions at compile time:
  1. Create temporary dictionary entries for each of the identifiers passed to (LOCAL), such that each identifier will behave as a local. These temporary dictionary entries shall vanish at the end of the definition, denoted by ; (semicolon), ;CODE, or DOES>. The system need not maintain these identifiers in the same way it does other dictionary entries as long as they can be found by normal dictionary searching processes. Furthermore, if the Search-Order word set is present, local identifiers shall always be searched before any of the word lists in any definable search order, and none of the Search-Order words shall change the locals' privileged position in the search order. Local identifiers may reside in mass storage.

  2. For each identifier passed to (LOCAL), the system shall generate an appropriate code sequence that does the following at execution time:

    1. Allocate a storage resource adequate to contain the value of a local. The storage shall be allocated in a way that does not preclude re-entrancy or recursion in the definition using the local.

    2. Initialize the value using the top item on the data stack. If more than one local is declared, the top item on the stack shall be moved into the first local identified, the next item shall be moved into the second, and so on.

    The storage resource may be the return stack or may be implemented in other ways, such as in registers. The storage resource shall not be the data stack. Use of locals shall not restrict use of the data stack before or after the point of declaration.

  3. Arrange that any of the legitimate methods of terminating execution of a definition, specifically ; (semicolon), ;CODE, DOES> or EXIT, will release the storage resource allocated for the locals, if any, declared in that definition. ABORT shall release all local storage resources, and CATCH / THROW (if implemented) shall release such resources for all definitions whose execution is being terminated.

  4. Separate sets of locals may be declared in defining words before DOES> for use by the defining word, and after DOES> for use by the word defined.

A system implementing the Locals word set shall support the declaration of at least sixteen locals in a definition.

13.3.3.2 Syntax restrictions

Immediate words in a program may use (LOCAL) to implement syntaxes for local declarations with the following restrictions:

  1. A program shall not compile any executable code into the current definition between the time (LOCAL) is executed to identify the first local for that definition and the time of sending the single required "last local" message;

  2. The position in program source at which the sequence of (LOCAL) messages is sent, referred to here as the point at which locals are declared, shall not lie within the scope of any control structure;

  3. Locals shall not be declared until values previously placed on the return stack within the definition have been removed;

  4. After a definition's locals have been declared, a program may place data on the return stack. However, if this is done, locals shall not be accessed until those values have been removed from the return stack;

  5. Words that return execution tokens, such as ' (tick), ['], or FIND, shall not be used with local names;

  6. A program that declares more than sixteen locals in a single definition has an environmental dependency;

  7. Locals may be accessed or updated within control structures, including do-loops;

  8. Local names shall not be referenced by POSTPONE and [COMPILE].

See: 3.4 The Forth text interpreter.

13.4 Additional documentation requirements

13.4.1 System documentation

13.4.1.1 Implementation-defined options

13.4.1.2 Ambiguous conditions

  • executing a named local while in interpretation state (13.6.1.0086 (LOCAL));
  • a local name ends in ":", "[", "^";
  • a local name is a single non-alphabetic character;
  • the text between {: and :} extends over more than one line;
  • {: ... :} is used more than once in a word.

13.4.1.3 Other system documentation

  • no additional requirements.

13.4.2 Program documentation

13.4.2.1 Environmental dependencies

13.4.2.2 Other program documentation

  • no additional requirements.

13.5 Compliance and labeling

13.5.1 Forth-2012 systems

The phrase "Providing the Locals word set" shall be appended to the label of any Standard System that provides all of the Locals word set.

The phrase "Providing name(s) from the Locals Extensions word set" shall be appended to the label of any Standard System that provides portions of the Locals Extensions word set.

The phrase "Providing the Locals Extensions word set" shall be appended to the label of any Standard System that provides all of the Locals and Locals Extensions word sets.

13.5.2 Forth-2012 programs

The phrase "Requiring the Locals word set" shall be appended to the label of Standard Programs that require the system to provide the Locals word set.

The phrase "Requiring name(s) from the Locals Extensions word set" shall be appended to the label of Standard Programs that require the system to provide portions of the Locals Extensions word set.

The phrase "Requiring the Locals Extensions word set" shall be appended to the label of Standard Programs that require the system to provide all of the Locals and Locals Extensions word sets.

13.6 Glossary

13.6.1 Locals words

13.6.2 Locals extension words

ContributeContributions

ruvavatar of ruv Recognizer for localsComment2020-06-10 02:47:06

May a local be unfindable via FIND in a standard Forth system?

The answer is not stated explicitly. But the consequence of other clauses is that yes, it may:

  1. Locals should be searched before the search order.
  2. FIND (as well as FIND-NAME) considers the search order only (if it's present).
  3. A system is not obligated to use FIND for finding definition names in the Forth text interpreter.

So, it means even more: FIND cannot find locals in a standard Forth system that provides the optional Search-Order word set.

In any case, the result is that the locals may be recognized by a recognizer before other Forth definitions.


What does the following phrase mean: "The system need not maintain these identifiers in the same way it does other dictionary entries as long as they can be found by normal dictionary searching processes" ? Does "they" refer to "other dictionary entries" or to "these identifiers"?

AntonErtlavatar of AntonErtl

The existence of the sentence "The system need not maintain ..." only makes sense if "they" refers to the locals. The other dictionary entries can be found with the normal dictionary searching processes anyway, so the sentence would be redundant if "they" referred to the other dictionary entries.

Two arguments for requiring that FIND-NAME/FIND find locals:

  1. FIND-NAME/FIND are "normal dictionary searching processes", so these words should find the locals according to that sentence.

  2. The intent of the Forth-94 committee (and also my intent when proposing FIND-NAME) was that it is possible to write a user-defined text interpreter, as outlined in the rationale for COMPILE,. There is no other standard way to find locals, so FIND and FIND-NAME should include this functionality.

An argument against:

  1. We did not mention locals in the specifications of FIND and FIND-NAME. But given the intent, that was an oversight, certainly on my part.

Looking at what existing systems do, I wrote the small test

: x c" fluffystunk" ; : foo locals| fluffystunk | [ x find cr .s 2drop ] ;

In VFX and Gforth, FIND finds fluffystunk; in SwiftForth, iForth, and lxf, FIND does not.

Apparently this has not been an issue for 26 years, so apparently nobody has used a user-defined text interpreter to process a program using locals on SwiftForth, iForth, or lxf; nor has anybody written a program that relies on FIND not finding locals, and let it run on VFX or Gforth. Still, I think that the standard should nail this issue down.

ruvavatar of ruv

Two arguments for requiring that FIND-NAME/FIND find locals

As I can see, we have some arguments not for requiring, but for allowing.

  1. I agree that "they" refers to identifiers of the locals. But it seems to me, "as long as they can be found" means that the corresponding statement is only applicable when locals "can be found by normal dictionary searching processes". It does not require that they should be found by "normal dictionary searching processes". OTOH, what is "normal dictionary searching processes"? And do we have non normal dictionary searching processes? This wording too fuzzy to produce strong arguments.

  2. Actually, there is no any standard way to find locals, despite the intention. So, I suggest to introduce such a way via recognizer.

Concerning FIND. I think, when the Search-Order word set is provided, we can allow FIND-NAME to find locals only via the search order (i.e., when they are implemented as some special word list that is appended to the top of search order). Otherwise, FIND-NAME cannot be implemented via TRAVARSE-WORDLIST. Also, some existent implementation become nonstandard.

So, we should allow, but should not require this approach.

I think, we should provide a recognizer for locals, that will works in any case.

ruvavatar of ruv

Correction: Otherwise (i.e., if FIND-NAME is required to search locals and allowed to do it beyond the search order), the function of FIND-NAME cannot be implemented via GET-ORDER and TRAVARSE-WORDLIST.

Reply New Version

JimPetersonavatar of JimPeterson Contradiction With do-loopsRequest for clarification2022-03-08 20:39:59

13.3.3.2.d seems to contradict 13.3.3.2.g, which says "... including do-loops", given that the run-time definition of DO and LOOP involve placing and removing loop-sys on/from the return stack. The way I read 13.3.3.2.d implies to me that the locals would not be accessible within the loop while 13.3.3.2.g explicitly says that they are. Perhaps I should interpret this to mean that some words that manipulate the return stack (e.g., DO and LOOP) have special conditions that still allow for locals, but if that's the case, I believe it should be more explicitly stated in the spec.

ruvavatar of ruv

Locals are not accessible for a program if the program has placed data on the return stack. The reason is that in the general case it's unknown at compile-time how many items will be placed on the return stack at run-time.

Locals are accessible for a program inside do-loop, since it's known at compile-time how many items will be placed on the return stack by do-loop at run-time, and the system can calculate at compile-time the corresponding offset to access locals.

AntonErtlavatar of AntonErtl

ruv is correct. Another perspective: 13.3.3.2c,d means that a Forth system can store locals on the return stack with few complications; 13.3.3.2g means that if it does that, it has to take DO...LOOP nesting into account when accessing locals (DO..LOOP also can, but is not required to store data on the return stack). By contrast, uses of >R, R> etc. do not have to be statically analysed (and in general, that is not possible, because the program can push a statically non-determinate value on the return stack). The use of a frame pointer would allow accessing locals in the face of statically indeterminate return stack effects, and is used by many (all?) Forth systems that keep locals on the return stack, but the standard authors apparently wanted to allow implementing locals on the return stack without frame pointer and therefore added 13.3.3.2d.

Closed

ruvavatar of ruv

For instance, a frame pointer is not used in SP-Forth/4, and local variables are accessed via the return stack pointer. loop-sys takes 3 cells on the return stack.

I guess, maintain a separate frame pointer is either less efficient (worse run-time performance) or more complex (requires more development/support time) than use of the return stack pointer for that.

Reply New Version

JimPetersonavatar of JimPeterson Accessing Remaining Data Stack?Request for clarification2022-03-08 20:58:26

No mention is explicitly made about whether or not the remainder of the data stack that was not loaded in to locals would still be accessible during execution of the definition. I can think of at least one implementation of support for locals that simply records a "frame pointer" (e.g., gforth's SP@) that points to the current data stack position, leaving all the locals right on the data stack and allowing read/write access through direct addressing, and then relocates any additional return values placed on the stack upon exit from the word. There is a strong implication that such an implementation, while "efficient", would not be compliant, but I feel like it would be beneficial for the spec to explicitly state, one way or another, whether or not accessing (or even dropping) items on the data stack below those pushed into locals should be allowed.

ruvavatar of ruv

No mention is explicitly made about whether or not the remainder of the data stack that was not loaded in to locals would still be accessible during execution of the definition.

It's mentioned explicitly via the stack diagrams for run-time semantics for {: and for LOCALS| (correspondingly):

Run-time: ( x1 ... xn -- )

Run-time: ( xn ... x2 x1 -- )

Also have a look at 2.2.2 Stack notation: "Only those stack items required for or provided by execution of the definition are shown". If nothing is shown in the "after" part of a stack diagram, then the parameters are only taken, and nothing is placed on the stack. In the case of the run-time semantics for locals initialization, it efficiently means that a system is not allowed to place a frame of local variables on the data stack.

What is missed is the stack diagram for the return stack: ( R: -- locals-sys ) (and the corresponding data type locals-sys), since they may place data on the return stack. But then the stack diagrams for the run-time semantics for exit and ; should be updated too: ( R: nest-sys -- | nest-sys locals-sys -- )

ruvavatar of ruv

What is missed is the stack diagram for the return stack: ( R: -- locals-sys )

Probably, a better variant is to rely on nest-sys: ( R: nest-sys1 -- nest-sys2 )

Then no need to update the stack diagrams for exit, etc.

Reply New Version