From: Jason Self Date: Mon, 28 Aug 2017 02:55:35 +0000 (-0700) Subject: language.md: Various updates X-Git-Url: https://jxself.org/git/?a=commitdiff_plain;h=dc57bb3220018e48a1436d5ec15286b591c1e122;p=mudman.git language.md: Various updates --- diff --git a/md/language.md b/md/language.md index ce0e3b4..1cbe16d 100644 --- a/md/language.md +++ b/md/language.md @@ -1,10 +1,4 @@ -% The Muddle Programming Language -% Greg Pfister - S. W. Galley - et al. -% 1979 - -MIT Technical Report 293 +wMIT Technical Report 293 Laboratory for Computer Science\ Massachusetts Institute of Technology\ @@ -19,21 +13,22 @@ This document is free of known copyright restrictions. Abstract ======== -The Muddle programming language began existence in late 1970 as a -successor to Lisp (Moon, 1974), a candidate vehicle for the Dynamic -Modeling System, and a possible base for implementation of Planner -(Hewitt, 1969). The original design goals included an interactive -integrated environment for programming, debugging, loading, and -editing: ease in learning and use; facilities for structured, modular, -shared programs; extensibility of syntax, data types and operators: -data-type checking for debugging and optional data-type declarations -for compiled efficiency; associative storage, coroutining, and -graphics. Along the way to reaching those goals, it developed flexible -input/output (including the ARPA Network), and flexible interrupt and -signal handling. It now serves as a base for software prototyping, -research, development, education, and implementation of the majority -of programs at MIT-DMS: a library of sharable modules, a coherent user -interface, special research projects, autonomous daemons, etc. +The Muddle programming language began existence in late 1970 (under +the name Muddle) as a successor to Lisp (Moon, 1974), a candidate +vehicle for the Dynamic Modeling System, and a possible base for +implementation of Planner (Hewitt, 1969). The original design goals +included an interactive integrated environment for programming, +debugging, loading, and editing: ease in learning and use; facilities +for structured, modular, shared programs; extensibility of syntax, +data types and operators: data-type checking for debugging and +optional data-type declarations for compiled efficiency; associative +storage, coroutining, and graphics. Along the way to reaching those +goals, it developed flexible input/output (including the ARPA +Network), and flexible interrupt and signal handling. It now serves as +a base for software prototyping, research, development, education, and +implementation of the majority of programs at MIT-DMS: a library of +sharable modules, a coherent user interface, special research +projects, autonomous daemons, etc. This document was originally intended to be a simple low-level introduction to Muddle. It has, however, acquired a case of @@ -73,8 +68,8 @@ For editing the content of this document and correcting some misconceptions, I would like to thank Chris Reeve, Bruce Daniels, and especially Gerald Sussman, one of whose good ideas I finally did use. -*Greg Pfister\ -December 15, 1972* +Greg Pfister\ +December 15, 1972 Since Greg left the fold, I have taken up the banner and updated his document. The main sources for small revisions have been the on-line @@ -97,8 +92,8 @@ richness of Muddle from the inside. I especially thank Chris Reeve ("the oracle") for the patience to answer questions and resolve doubts, as he no doubt as done innumerable times before. -*S. W. Galley\ -May 23, 1979* +S. W. Galley\ +May 23, 1979 This work was supported by the Advanced Research Projects Agency of the Department of Defense and was monitored by the Office of Naval @@ -143,7 +138,7 @@ reading, text within brackets like these should be ignored.\] Most specifically indicated examples herein are composed of pairs of lines. The first line of a pair, the input, always ends in `$` (which -is how the ASCII character ESC is represented, and which always +is how the ASCII character `ESC` is represented, and which always represents it). The second line is the result of Muddle's groveling over the first. If you were to type all the first lines at Muddle, it would respond with all the second lines. (More exactly, the "first @@ -159,8 +154,8 @@ but sometimes one of those will be ommitted, for obvious reasons. An ellipsis (...) indicates that something uninteresting has been omitted. The character `^` means that the following character is to be -"controllified": it is usually typed by holding down a terminal's CTRL -key and striking the other key. +"controllified": it is usually typed by holding down a terminal's +`CTRL` key and striking the other key. Chapter 1. Basic Introduction ============================= @@ -202,61 +197,61 @@ Typing a character at Muddle normally just causes that character to be echoed (printed on your terminal) and remembered in a buffer. The only characters for which this is normally not true act as follows: -Typing `$` (ESC) causes Muddle to echo dollar-sign and causes the +Typing `$` (`ESC`) causes Muddle to echo dollar-sign and causes the contents of the buffer (the characters which you've typed) to be interpreted as an expression(s) in Muddle. When this interpretation is done, the result will be printed and Muddle will wait for more typing. -ESC will be represented by the glyph `$` in this document. - -Typing the rubout character (DEL in the ITS and Top-20 versions, -CTRL+A in the Tenex version) causes the last character in the buffer --- the one most recently typed -- to be thrown away (deleted). If you -now immediately type another rubout, once again the last character is -deleted -- namely the second most recently typed. Etc. The character -deleted is echoed, so you can see what you're doing. On some "display" -terminals, rubout will "echo" by causing the deleted character to -disappear. If no characters are in the buffer, rubout echoes as a -carriage-return line-feed. - -Typing \^@ (CTRL+@) deletes everything you have typed since the last -`$`, and prints a carriage-return line-feed. - -Typing \^D (CTRL+D) causes the current input buffer to be typed back -out at you. This allows you to see what you really have, without the -confusing re-echoed characters produced by rubout. - -Typing \^L (CTRL+L) produces the same effect as typing \^D, except -that, if your terminal is a "display" terminal (for example, IMLAC, -ARDS, Datapoint), it firsts clears the screen. - -Typing \^G (CTRL+G) causes Muddle to stop whatever it is doing and act -as if an error had occurred ([section -1.4](#14-errors-simple-considerations-1)). \^G is generally most +`ESC` will be represented by the glyph `$` in this document. + +Typing the rubout character (`DEL` in the ITS and Top-20 versions, +`CTRL`+`A` in the Tenex version) causes the last character in the +buffer -- the one most recently typed -- to be thrown away (deleted). +If you now immediately type another rubout, once again the last +character is deleted -- namely the second most recently typed. Etc. +The character deleted is echoed, so you can see what you're doing. On +some "display" terminals, rubout will "echo" by causing the deleted +character to disappear. If no characters are in the buffer, rubout +echoes as a carriage-return line-feed. + +Typing `^@` (`CTRL`+`@`) deletes everything you have typed since the +last `$`, and prints a carriage-return line-feed. + +Typing `^D` (`CTRL`+`D`) causes the current input buffer to be typed +back out at you. This allows you to see what you really have, without +the confusing re-echoed characters produced by rubout. + +Typing `^L` (`CTRL`+`L`) produces the same effect as typing `^D`, +except that, if your terminal is a "display" terminal (for example, +IMLAC, ARDS, Datapoint), it firsts clears the screen. + +Typing `^G` (`CTRL`+`G`) causes Muddle to stop whatever it is doing +and act as if an error had occurred ([section +1.4](#14-errors-simple-considerations-1)). `^G` is generally most useful for temporary interruptions to check the progress of a -computation. \^G is "reversible" -- that is, it does not destroy any -of the "state" of the computation it interrupts. To "undo" a \^G, type -the characters +computation. `^G` is "reversible" -- that is, it does not destroy any +of the "state" of the computation it interrupts. To "undo" a `^G`, +type the characters $ (This is discussed more fully far below, in section 16.4.) -Typing \^S (CTRL+S) causes Muddle to **throw away** what it is +Typing `^S` (`CTRL`+`S`) causes Muddle to **throw away** what it is currently doing and return a normal "listening" state. (In the Tenex -and Tops-20 versions, \^O also should have the same effect.) \^S is +and Tops-20 versions, `^O` also should have the same effect.) `^S` is generally most useful for aborting infinite loops and similar terrible -things. \^S **destroys** whatever is going on, and so it is **not** +things. `^S` **destroys** whatever is going on, and so it is **not** reversible. Most expressions in Muddle include "brackets" (generically meant) that must be correctly paired and nested. If you end your typing with the -pair of characters `!$` (!+ESC), all currently unpaired brackets (but -not double-quotes, which bracket strings of characters) will -automatically be paired and interpretation will start. Without the !, -Muddle will just sit there waiting for you to pair them. If you have -improperly nested parentheses, brackets, etc., within the expression -you typed, an error will occur, and Muddle will tell you what is -wrong. +pair of characters `!$` (`!`+`ESC`), all currently unpaired brackets +(but not double-quotes, which bracket strings of characters) will +automatically be paired and interpretation will start. Without the +`!`, Muddle will just sit there waiting for you to pair them. If you +have improperly nested parentheses, brackets, etc., within the +expression you typed, an error will occur, and Muddle will tell you +what is wrong. Once the brackets are properly paired, Muddle will immediately echo carriage-return and line-feed, and the next thing it prints will be @@ -264,8 +259,8 @@ the result of the evaluation. Thus, if a plain `$` is not so echoed, you have some expression unclosed. In that case, if you have not typed any characters beyond the `$`, you can usually rub out the `$` and other characters back to the beginning of the unclosed expression. -Otherwise, what you have typed is beyond the help of rubout and \^@; -if you want to abort it, use \^S. +Otherwise, what you have typed is beyond the help of rubout and `^@`; +if you want to abort it, use `^S`. Muddle accepts and distinguishes between upper and lower case. All "built-in functions" must be referenced in upper case. @@ -583,9 +578,9 @@ brackets to be closed. In other cases, they will produce errors during met. Instead, the right-hand column will be used to state just what `READ` thought the input in the left-hand column really was. - -------------------------------------------------------------------------------- + ------------------------------------------------------------------------------------ Input Explanation - --------------------------- ---------------------------------------------------- + --------------------------- -------------------------------------------------------- `ABC$` an `ATOM` of `PNAME` `ABC` `abc$` an `ATOM` of `PNAME` `abc` @@ -608,9 +603,9 @@ met. Instead, the right-hand column will be used to state just what something else (The something else will contain an `ATOM` of `PNAME` beginning `cd.`) - `12345A34$` an `ATOM` of `PNAME` `12345A35` (If the A had been - an E, the object would have been a `FLOAT`.) - -------------------------------------------------------------------------------- + `12345A34$` an `ATOM` of `PNAME` `12345A35` (If the A had been an E, + the object would have been a `FLOAT`.) + ------------------------------------------------------------------------------------ #### 2.6.3.3.  (Backslash) in ATOMs @@ -639,19 +634,19 @@ non-standard, this time not because anything is unfinished or in error, but because commenting is needed: `PRINT` doesn't do it full justice. - --------------------------------------------------------------------------- + ------------------------------------------------------------------------------- Input Explanation - ------------------------ -------------------------------------------------- + ------------------------ ------------------------------------------------------ `a\ one\ and\ a\ two$` one `ATOM`, whose `PNAME` has four spaces in it - `1234\56789$` an `ATOM` of `PNAME` `123456789`, which `PRINT`s - as `\1233456789` + `1234\56789$` an `ATOM` of `PNAME` `123456789`, which `PRINT`s as + `\1233456789` `123\ $` an `ATOM` of `PNAME` `123space`, which `PRINT`s as `\123\`, with a space on the end `\\$` an `ATOM` whose `PNAME` is a single backslash - --------------------------------------------------------------------------- + ------------------------------------------------------------------------------- Chapter 3. Built-in Functions ============================= @@ -3884,7 +3879,7 @@ which are more fully explained in chapter 11. Another example can be found in chapter 13. Example: the following `FUNCTION` reads characters from the current -input channel until an `$` (ESC) is read, and then returns what was +input channel until an `$` (`ESC`) is read, and then returns what was read as one `STRING`. (The `SUBR` `READCHR` reads one character from the input channel and returns it. `NEXTCHR` returns the next `CHARACTER` which `READCHR` will return -- chapter 11.) @@ -3998,8 +3993,8 @@ discussion of which will be deferred until later. ### 11.1.1. Input All of the following input Subroutines, when directed at a terminal, -hang until `$` (ESC) is typed and allow normal use of rubout, \^D, \^L -and \^@. +hang until `$` (`ESC`) is typed and allow normal use of `rubout`, +`^D`, `^L` and `^@`. #### 11.1.1.1. READ @@ -4131,30 +4126,30 @@ used on the `CHANNEL`, and whether or not the *device* is a terminal. The following table tells which `SUBR`s can be used with which modes, where `OK` indicates an allowed use: - ------------------------------------------------------------------------------------------------------------------------------------------- - "READ" "PRINT" "READB" "PRINTB", "PRINTO" mode / SUBRs - -------------------- -------------------- -------------------- ------------------------------------------ --------------------------------- - OK OK `READ` `READCHR` `NEXTCHR` - `READSTRING` `FILECOPY` - `FILE-LENGTH LOAD` + ------------------------------------------------------------------------------------------------------------------------------------------------- + "READ" "PRINT" "READB" "PRINTB", "PRINTO" mode / SUBRs + -------------------- --------------------- --------------------- -------------------------------------------- ----------------------------------- + OK OK `READ` `READCHR` `NEXTCHR` + `READSTRING` `FILECOPY` + `FILE-LENGTH LOAD` - OK OK\* `PRINT` `PRIN1` `PRINC` `IMAGE` - `CRLF` `TERPRI` `FILECOPY` - `PRINTSTRING` `BUFOUT` `NETS` - `RENAME` + OK OK\* `PRINT` `PRIN1` `PRINC` `IMAGE` + `CRLF` `TERPRI` `FILECOPY` + `PRINTSTRING` `BUFOUT` `NETS` + `RENAME` - OK `READB` `GC-READ` + OK `READB` `GC-READ` - OK `PRINTB` `GC-DUMP` + OK `PRINTB` `GC-DUMP` - OK OK OK `ACCESS` + OK OK OK `ACCESS` - OK OK OK OK `RESET` + OK OK OK OK `RESET` - OK OK `ECHOPAIR` + OK OK `ECHOPAIR` - OK `TTYECHO` `TYI` - ------------------------------------------------------------------------------------------------------------------------------------------- + OK `TTYECHO` `TYI` + ------------------------------------------------------------------------------------------------------------------------------------------------- `*` PRINTing (or `PRIN1`ing) an `RSUBR` (chapter 19) on a `"PRINTB"` or `"PRINTO"` `CHANNEL` has special effects. @@ -4277,52 +4272,52 @@ each element, and an interpretation. The format used is the following: *element-number: type interpretation* - ------------------------------------------------------------------------------------------------ - element-number type interpretation - ------------------------- ------------------ --------------------------------------------------- - -1 `LIST` transcript channel(s) (see below) + ---------------------------------------------------------------------------------------------------- + element-number type interpretation + -------------------------- ------------------ ------------------------------------------------------ + -1 `LIST` transcript channel(s) (see below) - \* 0 varies device-dependent information + \* 0 varies device-dependent information - \* 1 `FIX` channel number (ITS) or JFN (Tenex and Tops-20), - `0` for internal or closed + \* 1 `FIX` channel number (ITS) or JFN (Tenex and Tops-20), `0` + for internal or closed - \* 2 `STRING` mode + \* 2 `STRING` mode - \* 3 `STRING` first file name argument + \* 3 `STRING` first file name argument - \* 4 `STRING` second file name argument + \* 4 `STRING` second file name argument - \* 5 `STRING` device name argument + \* 5 `STRING` device name argument - \* 6 `STRING` directory name argument + \* 6 `STRING` directory name argument - \* 7 `STRING` real first file name + \* 7 `STRING` real first file name - \* 8 `STRING` real second file name + \* 8 `STRING` real second file name - \* 9 `STRING` real device name + \* 9 `STRING` real device name - \* 10 `STRING` real directory name + \* 10 `STRING` real directory name - \* 11 `FIX` various status bits + \* 11 `FIX` various status bits - \* 12 `FIX` PDP-10 instruction used to do one I/O operation + \* 12 `FIX` PDP-10 instruction used to do one I/O operation - 13 `FIX` number of characters per line of output + 13 `FIX` number of characters per line of output - 14 `FIX` current character position on a line + 14 `FIX` current character position on a line - 15 `FIX` number of lines per page + 15 `FIX` number of lines per page - 16 `FIX` current line number on a page + 16 `FIX` current line number on a page - 17 `FIX` access pointer for file-oriented devices + 17 `FIX` access pointer for file-oriented devices - 18 `FIX` radix for `FIX` conversion + 18 `FIX` radix for `FIX` conversion - 19 `FIX` sink for an internal `CHANNEL` - ------------------------------------------------------------------------------------------------ + 19 `FIX` sink for an internal `CHANNEL` + ---------------------------------------------------------------------------------------------------- N.B.: The elements of a `CHANNEL` below number 1 are usually invisible but are obtainable via ` fix>`, for some appropriate @@ -4573,8 +4568,8 @@ execution upon `RESTORE`ation. eventually returns `"DONE"`. First, however, it `READ`s and `EVAL`s every Muddle object in the file pointed to by *input*, and then -`CLOSE`s *input*. Any occurrences of rubout, ^@, ^D, \^L, etc., in the -file are given no special meaning; they are simply `ATOM` +`CLOSE`s *input*. Any occurrences of `rubout`, `^@`, `^D`, `^L`, etc., +in the file are given no special meaning; they are simply `ATOM` constituents. *look-up* is optional, used to specify a `LIST` of `OBLIST`s for the @@ -4739,8 +4734,8 @@ available, that is, when `READCHR` would return `-1`. returns its first argument, after making the two `CHANNEL`s "know -about each other" so that rubout, ^@, ^D and \^L on *terminal-in* will -cause the appropriate output on *terminal-out*. +about each other" so that `rubout`, `^@`, `^D` and `^L` on +*terminal-in* will cause the appropriate output on *terminal-out*. ### 11.8.2. TTYECHO @@ -4757,9 +4752,9 @@ fashion. returns one `CHARACTER` from *channel* (optional, `.INCHAN` by -default) when it is typed, rather than after `$` (ESC) is typed, as is -the case with `READCHR`. The following example echos input characters -as their ASCII values, until a carriage-return is typed: +default) when it is typed, rather than after `$` (`ESC`) is typed, as +is the case with `READCHR`. The following example echos input +characters as their ASCII values, until a carriage-return is typed: >)) >>> @@ -5020,7 +5015,10 @@ explicit structures, etc., without being bothered by what function it should use to do so. This is particularly true with respect to locatives to `LVAL`s; the fact that they are independent of changes in binding can save a lot of fooling around with `EVAL` and -`ENVIRONMENT`s. \# Chapter 13. Association (Properties) +`ENVIRONMENT`s. + +Chapter 13. Association (Properties) +==================================== There is an "associative" data storage and retrieval system embedded in Muddle which allows the construction of data structures with @@ -6301,11 +6299,11 @@ objects that you have typed in and Muddle has typed out. If the `ATOM` inputs (what `READ` returns) in it, most recent first. Similarly, if the `ATOM` `L-OUTS` has a local value that is a `LIST`, `LISTEN` will keep recent outputs (what `EVAL` returns) in it, most recent first. -The keeping is done before the `PRINT`ing, so that \^S does not defeat -its purpose. The user can decide how much to keep around by setting -the length of each `LIST`. Even if `L-OUTS` is not used, the atom -`LAST-OUT` is always `SET` to the last object returned by `EVAL` in -the standard `LISTEN` loop. Example: +The keeping is done before the `PRINT`ing, so that `^S` does not +defeat its purpose. The user can decide how much to keep around by +setting the length of each `LIST`. Even if `L-OUTS` is not used, the +atom `LAST-OUT` is always `SET` to the last object returned by `EVAL` +in the standard `LISTEN` loop. Example: $ (NEWEST NEWER NEW) @@ -6487,19 +6485,19 @@ the `FLOAD`. Example: 16.7. Control-G (\^G) -Typing control-G (\^G, ``) at Muddle causes it to act just as -if an error had occurred in whatever was currently being done. You can -then examine the values of variables as above, continue by applying -`ERRET` to one argument (which is ignored), `RETRY` a `FRAME` lower on -the control stack, or flush everything by applying `ERRET` to no -arguments. +Typing control-G (`^G`, ``) at Muddle causes it to act just +as if an error had occurred in whatever was currently being done. You +can then examine the values of variables as above, continue by +applying `ERRET` to one argument (which is ignored), `RETRY` a `FRAME` +lower on the control stack, or flush everything by applying `ERRET` to +no arguments. 16.8. Control-S (\^S) -Typing control-S (\^S, ``) at Muddle causes it to stop what +Typing control-S (`^S`, ``) at Muddle causes it to stop what is happening and return to the `FRAME` `.LERR\ !-INTERRUPTS`, -returning the `ATOM` `T`. (In the Tenex and Tops-20 versions, \^O also -has the same effect.) +returning the `ATOM` `T`. (In the Tenex and Tops-20 versions, `^O` +also has the same effect.) 16.9. OVERFLOW @@ -7482,8 +7480,7 @@ SUM3 could be have been written as: ) - >>>>> + >>>>> 20.7. Other Coroutining Features -------------------------------- @@ -8013,9 +8010,9 @@ two arguments: the `CHARACTER` which was typed, and the `CHANNEL` on which it was typed. In the ITS version, the "interesting" characters are those "enabled -for interrupts" on a real terminal, namely \^@ through -\^G, \^K through \^\_, and -DEL (that is, ASCII codes 0-7, 13-37, and 177 octal.) +for interrupts" on a real terminal, namely `^@` through `^G`, `^K` +through `^_`, and `DEL` (that is, ASCII codes 0-7, 13-37, and 177 +octal.) In the Tenex and Tops-20 versions, the operating system can be told which characters typed on a terminal should cause this interrupt to @@ -8023,22 +8020,21 @@ occur, by calling the `SUBR` `ACTIVATE-CHARS` with a `STRING` argument containing those characters (no more than six, all with ASCII codes less than 33 octal). If called with no argument, `ACTIVATE-CHARS` returns a `STRING` containing the characters that currently interrupt. -Initially, only \^G, \^S, and \^O -interrupt. +Initially, only `^G`, `^S`, and `^O` interrupt. An initial Muddle already has `"CHAR"` enabled on `,INCHAN` with a priority 8 (eight), the `SUBR` `QUITTER` for a handler to run in -`#PROCESS 0` (the running `PROCESS`); this is how `^G` and -`^S` are processed. In addition, every time a new `CHANNEL` -is `OPEN`ed in `"READ"` mode to a terminal, a similar `IHEADER` and -`HANDLER` are associated with that new `CHANNEL` automatically. These +`#PROCESS 0` (the running `PROCESS`); this is how `^G` and `^S` are +processed. In addition, every time a new `CHANNEL` is `OPEN`ed in +`"READ"` mode to a terminal, a similar `IHEADER` and `HANDLER` are +associated with that new `CHANNEL` automatically. These automatically-generated `IHEADER`s and `HANDLER`s use the standard machinery, and they can be `DISABLE`d or `OFF`ed at will. **However**, the `IHEADER` for `,INCHAN` should not be `OFF`ed: Muddle knows that `$` is typed only by an interrupt! Example: the following causes the given message to be printed out -whenever a `^Y` is typed on `.INCHAN`: +whenever a `^Y` is typed on `.INCHAN`: #FUNCTION ((CHAR CHAN) @@ -8164,10 +8160,10 @@ character. ### 21.8.8. "UNBLOCKED" -`"UNBLOCKED"` occurs whenever a `$` (`ESC`) is typed on a -terminal if a program was hanging and waiting for input, or when a TYI -call (which see) is satisfied. A handler takes one argument: the -`CHANNEL` via which the `$` or character is input. +`"UNBLOCKED"` occurs whenever a `$` (`ESC`) is typed on a terminal if +a program was hanging and waiting for input, or when a TYI call (which +see) is satisfied. A handler takes one argument: the `CHANNEL` via +which the `$` or character is input. ### 21.8.9. "READ" and "WRITE" @@ -9087,8 +9083,7 @@ is probably worthwhile if a *special* is referenced more than once, or if an *unmanifest* is referenced more than twice. Example: >) + #DECL ((VALUE) VECTOR (THINGS DB) >) > .THINGS>> 24.4. Global and Local Values @@ -9185,22 +9180,22 @@ Appendix 1. A Look Inside ========================= This appendix tells about the mapping between Muddle objects and -PDP-10 storage -- in other words, the way things look "on the -inside". None of this information is essential to knowing how to -program in Muddle, but it does give some reasons for capabilities and +PDP-10 storage -- in other words, the way things look "on the inside". +None of this information is essential to knowing how to program in +Muddle, but it does give some reasons for capabilities and restrictions that otherwise you have to memorize. The notation and -terminology get a little awkward in this discussion, because we are -in a twilight zone between the worlds of Muddle objects and of bit -patterns. In general the words and phrases appearing in diagrams -refer to bit patterns not Muddle objects. A lower-case word (like -"tuple") refers to the storage occupied by an object of the -corresponding `PRIMTYPE` (like `TUPLE`). +terminology get a little awkward in this discussion, because we are in +a twilight zone between the worlds of Muddle objects and of bit +patterns. In general the words and phrases appearing in diagrams refer +to bit patterns not Muddle objects. A lower-case word (like "tuple") +refers to the storage occupied by an object of the corresponding +`PRIMTYPE` (like `TUPLE`). First some terminology needs discussion. The sine qua non of any Muddle object is a **pair** of 36-bit computer words. In general, lists consist of pairs chained together by pointers (addresses), and -vectors consist of contiguous blocks of pairs. `==?` essentially -tests two pairs to see whether they contain the same bit patterns. +vectors consist of contiguous blocks of pairs. `==?` essentially tests +two pairs to see whether they contain the same bit patterns. The first (lower-addressed) word of a pair is called the **`TYPE` word**, because it contains a numeric **`TYPE` code** that represents @@ -9231,14 +9226,14 @@ cause `"READ"` and `"WRITE"` interrupts on read and write references to the pair. The next bit is used to differentiate between list elements and vector dope words. The next bit is unused but could be used in the future for an "execute" monitor. The remaining 13 bits -specify the actual `TYPE` code. What `CHTYPE` does is to copy the -pair and put a new `TYPE` code into the new pair. +specify the actual `TYPE` code. What `CHTYPE` does is to copy the pair +and put a new `TYPE` code into the new pair. Each data `TYPE` (predefined and `NEWTYPE`s) must belong to one of -about 25 "storage allocation classes" (roughly corresponding to -Muddle `PRIMTYPE`s). These classes are characterized primarily by the -manner in which the garbage collector treats them. Some of these -classes will now be described. +about 25 "storage allocation classes" (roughly corresponding to Muddle +`PRIMTYPE`s). These classes are characterized primarily by the manner +in which the garbage collector treats them. Some of these classes will +now be described. "One Word" @@ -9271,11 +9266,11 @@ no elements, `pointer` is zero; thus empty objects of `PRIMTYPE` Members of this class are all "counting pointers" to blocks of two-word pairs. The right half of a counting pointer is an address, -and the left half is the negative of the number of 36-bit words in -the block. (This format is tailored to the PDP-10 `AOBJN` -instruction.) The number of pairs in the block (`LENGTH`) is half -that number, since each pair is two words. All external `TYPE`s in -this class are of `PRIMTYPE` `VECTOR`. Example: +and the left half is the negative of the number of 36-bit words in the +block. (This format is tailored to the PDP-10 `AOBJN` instruction.) +The number of pairs in the block (`LENGTH`) is half that number, since +each pair is two words. All external `TYPE`s in this class are of +`PRIMTYPE` `VECTOR`. Example: --------------------------------- | VECTOR | 0 | @@ -9284,8 +9279,8 @@ this class are of `PRIMTYPE` `VECTOR`. Example: --------------------------------- where `length` is the `LENGTH` of the `VECTOR` and `pointer` is the -location of the start (the element selected by an `NTH` argument of -1) of the `VECTOR`. +location of the start (the element selected by an `NTH` argument of 1) +of the `VECTOR`. "N word" @@ -9309,14 +9304,14 @@ to the beginning of the `UVECTOR`. "Byte String" and "Character String" -These two classes are almost identical. Byte strings are byte -pointers to strings of arbitrary-size bytes. `PRIMTYPE` `BYTES` is -the only member of this class. Character strings are byte pointers to -strings of ASCII characters. `PRIMTYPE` `STRING` is the only member -of this class. Both of these classes consist of a length and a PDP-10 -byte pointer. In the case of character strings, the byte-size field -in the byte pointer is always seven bits per byte (hence five bytes -per word). Example: +These two classes are almost identical. Byte strings are byte pointers +to strings of arbitrary-size bytes. `PRIMTYPE` `BYTES` is the only +member of this class. Character strings are byte pointers to strings +of ASCII characters. `PRIMTYPE` `STRING` is the only member of this +class. Both of these classes consist of a length and a PDP-10 byte +pointer. In the case of character strings, the byte-size field in the +byte pointer is always seven bits per byte (hence five bytes per +word). Example: --------------------------------- | STRING | length | @@ -9329,8 +9324,8 @@ where `length` is the `LENGTH` of the `STRING` (in bytes) and string (an `ILDB` instruction is needed to get the first byte). A newly-created `STRING` always has `*010700*` in the left half of `byte-pointer`. Unless the string was created by `SPNAME`, -`byte-pointer` points to a uvector, where the elements (characters) -of the `STRING` are stored, packed together five to a word. +`byte-pointer` points to a uvector, where the elements (characters) of +the `STRING` are stored, packed together five to a word. "Frame" @@ -9338,8 +9333,8 @@ This class gives the user program a handle on its control and variable-reference structures. All external `TYPE`s in this class are of `PRIMTYPE` `FRAME`. Three numbers are needed to designate a frame: a unique 18-bit identifying number, a pointer to the frame's storage -on a control stack, and a pointer to the `PROCESS` associated with -the frame. Example: +on a control stack, and a pointer to the `PROCESS` associated with the +frame. Example: --------------------------------- | FRAME |PROCESS-pointer| @@ -9358,8 +9353,8 @@ A tuple pointer is a counting pointer to a vector on the control stack. It may be a pointer to the arguments to a Subroutine or a pointer generated by the `"TUPLE"` declaration in a `FUNCTION`. Like objects in the previous class, these objects contain a unique -identifying number used for validation. `PRIMTYPE` `TUPLE` is the -only member of this class. Example: +identifying number used for validation. `PRIMTYPE` `TUPLE` is the only +member of this class. Example: --------------------------------- | TUPLE | unique-id | @@ -9370,23 +9365,22 @@ only member of this class. Example: Other Storage Classes The rest of the storage classes include strictly internal `TYPE`s and -pointers to special kinds of lists and vectors like locatives, -`ATOM`s and `ASOC`s. A pair for any `LOCATIVE` except a `LOCD` looks -like a pair for the corresponding structure, except of course that -the `TYPE` is different. A `LOCD` pair looks like a tuple pair and -needs a word and a half for its value; the `unique-id` refers to a -binding on the control stack or to the "global stack" if zero. Thus -`LOCD`s are in a sense "stack objects" and are more restricted than -other locatives. +pointers to special kinds of lists and vectors like locatives, `ATOM`s +and `ASOC`s. A pair for any `LOCATIVE` except a `LOCD` looks like a +pair for the corresponding structure, except of course that the `TYPE` +is different. A `LOCD` pair looks like a tuple pair and needs a word +and a half for its value; the `unique-id` refers to a binding on the +control stack or to the "global stack" if zero. Thus `LOCD`s are in a +sense "stack objects" and are more restricted than other locatives. An `OFFSET` is stored with the `INDEX` in the right half of the value -word and the Pattern in the left half. Since the Pattern can be -either an `ATOM` or a `FORM`, the left half actually points to a -pair, which points to the actual Pattern. The Patttern `ANY` is -recognized as a special case: the left-half pointer is zero, and no -pair is used. Thus, if you're making the production version of your -program and want to save some storage, can do something like `>` for all `OFFSET`s. +word and the Pattern in the left half. Since the Pattern can be either +an `ATOM` or a `FORM`, the left half actually points to a pair, which +points to the actual Pattern. The Patttern `ANY` is recognized as a +special case: the left-half pointer is zero, and no pair is used. +Thus, if you're making the production version of your program and want +to save some storage, can do something like +`>` for all `OFFSET`s. Basic Data Structures --------------------- @@ -9394,8 +9388,8 @@ Basic Data Structures Lists List elements are pairs linked together by the right halves of their -first words. The list is terminated by a zero in the right half of -the last pair. For example the `LIST` `(1 2 3)` would look like this: +first words. The list is terminated by a zero in the right half of the +last pair. For example the `LIST` `(1 2 3)` would look like this: ------------- | LIST | 0 | @@ -9405,19 +9399,19 @@ the last pair. For example the `LIST` `(1 2 3)` would look like this: | 1 | | 2 | | 3 | ----------- ----------- ----------- -The use of pointers to tie together elements explains why new -elements can be added easily to a list, how sharing and circularity -work, etc. The links go in only one direction through the list, which -is why a list cannot be `BACK`ed or `TOP`ped: there's no way to find -the `REST`ed elements. +The use of pointers to tie together elements explains why new elements +can be added easily to a list, how sharing and circularity work, etc. +The links go in only one direction through the list, which is why a +list cannot be `BACK`ed or `TOP`ped: there's no way to find the +`REST`ed elements. Since some Muddle values require a word and a half for the value in -the pair, they do not fit directly into list elements. This problem -is solved by having "deferred pointers". Instead of putting the datum +the pair, they do not fit directly into list elements. This problem is +solved by having "deferred pointers". Instead of putting the datum directly into the list element, a pointer to another pair is used as -the value with the special internal `TYPE` `DEFER`, and the real -datum is put in the deferred pair. For example the `LIST` `(1 "hello" -3)` would look like this: +the value with the special internal `TYPE` `DEFER`, and the real datum +is put in the deferred pair. For example the `LIST` `(1 "hello" 3)` +would look like this: ------------- | LIST | 0 | @@ -9438,9 +9432,9 @@ Vectors A vector is a block of contiguous words. More than one pair can point to the block, possibly at different places in the block; this is how sharing occurs among vectors. Pointers that are different arise from -`REST` or `GROW`/`BACK` operations. The block is followed by two -"dope words", at addresses just larger than the largest address in -the block. Dope words have the following format: +`REST` or `GROW`/`BACK` operations. The block is followed by two "dope +words", at addresses just larger than the largest address in the +block. Dope words have the following format: / / | | @@ -9457,11 +9451,11 @@ The various fields have the following meanings: octal) is always one, to distinguish these vector dope words from a `TYPE`/value pair. -If the high-order bit is zero, then the vector is a `UVECTOR`, and -the remaining bits specify the uniform `TYPE` of the elements. -`CHUTYPE` just puts a new `TYPE` code in this field. Each element is -limited to a one-word value: clearly `PRIMTYPE` `STRING`s and -`BYTES`es and stack objects can't go in uniform vectors. +If the high-order bit is zero, then the vector is a `UVECTOR`, and the +remaining bits specify the uniform `TYPE` of the elements. `CHUTYPE` +just puts a new `TYPE` code in this field. Each element is limited to +a one-word value: clearly `PRIMTYPE` `STRING`s and `BYTES`es and stack +objects can't go in uniform vectors. If the high-order bit is one and the `TYPE` bits are zero, then this is a regular `VECTOR`. @@ -9472,10 +9466,10 @@ then this is either an `ATOM`, a `PROCESS`, an `ASOC`, or a described a little later in this appendix. `length` -- The high-order bit is the mark bit, used by the garbage -collector. The rest of this field specifies the number of words in -the block, including the dope words. This differs from the length -given in pairs pointing to this vector, since such pairs may be the -result of `REST` operations. +collector. The rest of this field specifies the number of words in the +block, including the dope words. This differs from the length given in +pairs pointing to this vector, since such pairs may be the result of +`REST` operations. `grow` -- This is actually two nine-bit fields, specifying either growth or shrinkage at both the high and low ends of the vector. The @@ -9550,25 +9544,25 @@ following format: If the type field corresponds to `TYPE` `UNBOUND`, then the `ATOM` is locally and globally unbound. (This is different from a pair, where the same `TYPE` `UNBOUND` is used to mean unassigned.) If it -corresponds to `TYPE` `LOCI` (an internal `TYPE`), then the value -cell points either to the global stack, if `bindid` is zero, or to a -local control stack, if `bindid` is non-zero. The `bindid` field is -used to verify whether the local value pointed to by the value cell -is valid in the current environment. The `pointer-to-OBLIST` is -either a counting pointer to an oblist (uvector). a positive offset -into the "transfer vector" (for pure `ATOM`s), or zero, meaning that -this `ATOM` is not on an `OBLIST`. The `valid-type` field tells -whether or not the `ATOM` represents a `TYPE` and if so the code for -that `TYPE`: `grow` values are never needed for atoms. +corresponds to `TYPE` `LOCI` (an internal `TYPE`), then the value cell +points either to the global stack, if `bindid` is zero, or to a local +control stack, if `bindid` is non-zero. The `bindid` field is used to +verify whether the local value pointed to by the value cell is valid +in the current environment. The `pointer-to-OBLIST` is either a +counting pointer to an oblist (uvector). a positive offset into the +"transfer vector" (for pure `ATOM`s), or zero, meaning that this +`ATOM` is not on an `OBLIST`. The `valid-type` field tells whether or +not the `ATOM` represents a `TYPE` and if so the code for that `TYPE`: +`grow` values are never needed for atoms. Associations -Associations are also special vector-like objects. The first six -words of the block contain `TYPE`/value pairs for the `ITEM`, -`INDICATOR` and `AVALUE` of the `ASOC`. The next word contains -forward and backward pointers in the chain for that bucket of the -association hash table. The last word contains forward and backward -pointers in the chain of all the associations. +Associations are also special vector-like objects. The first six words +of the block contain `TYPE`/value pairs for the `ITEM`, `INDICATOR` +and `AVALUE` of the `ASOC`. The next word contains forward and +backward pointers in the chain for that bucket of the association hash +table. The last word contains forward and backward pointers in the +chain of all the associations. --------------------------------- | ITEM | @@ -9603,58 +9597,56 @@ Templates In a template, the number in the type field (left half or first dope word) identifies to which "storage allocation class" this `TEMPLATE` -belongs, and it is used to find PDP-10 instructions in internal -tables (frozen uvectors) for performing `LENGTH`, `NTH`, and `PUT` -operations on any object of this `TYPE`. The programs to build these -tables are not part of the interpreter, but the interpreter does know -how to use them properly. The compiler can put these instructions -directly in compiled programs if a `TEMPLATE` is never `REST`ed; -otherwise it must let the interpreter discover the appropriate -instruction. The value word of a template pair contains, not a -counting pointer, but the number of elements that have been `REST`ed -off in the left half and a pointer to the first dope word in the -right half. +belongs, and it is used to find PDP-10 instructions in internal tables +(frozen uvectors) for performing `LENGTH`, `NTH`, and `PUT` operations +on any object of this `TYPE`. The programs to build these tables are +not part of the interpreter, but the interpreter does know how to use +them properly. The compiler can put these instructions directly in +compiled programs if a `TEMPLATE` is never `REST`ed; otherwise it must +let the interpreter discover the appropriate instruction. The value +word of a template pair contains, not a counting pointer, but the +number of elements that have been `REST`ed off in the left half and a +pointer to the first dope word in the right half. The Control Stack ----------------- -Accumulators with symbolic names `AB`, `TB`, and `TP` are all -pointers into the `RUNNING` `PROCESS`'s control stack. `AB` -("argument base") is a pointer to the arguments to the Subroutine now -being run. It is set up by the Subroutine-call mediator, and its old -value is always restored after a mediated Subroutine call returns. -`TB` ("temporaries base") points to the frame for the running -Subroutine and also serves as a stack base pointer. The `TB` pointer -is really all that is necessary to return from a Subroutine -- given -a value to return, for example by `ERRET` -- since the frame -specifies the entire state of the calling routine. `TP` ("temporaries -pointer") is the actual stack pointer and always points to the -current top of the control stack. +Accumulators with symbolic names `AB`, `TB`, and `TP` are all pointers +into the `RUNNING` `PROCESS`'s control stack. `AB` ("argument base") +is a pointer to the arguments to the Subroutine now being run. It is +set up by the Subroutine-call mediator, and its old value is always +restored after a mediated Subroutine call returns. `TB` ("temporaries +base") points to the frame for the running Subroutine and also serves +as a stack base pointer. The `TB` pointer is really all that is +necessary to return from a Subroutine -- given a value to return, for +example by `ERRET` -- since the frame specifies the entire state of +the calling routine. `TP` ("temporaries pointer") is the actual stack +pointer and always points to the current top of the control stack. While we're on the subject of accumulators, we might as well be complete. Each accumulator contains the value word of a pair, the -corresponding `TYPE` words residing in the `RUNNING` `PROCESS` -vector. When a `PROCESS` is not `RUNNING` (or when the garbage -collector is running), the accumulator contents are stored in the -vector, so that the Objects they point to look like elements of the -`PROCESS` and thus are not garbage-collectible. +corresponding `TYPE` words residing in the `RUNNING` `PROCESS` vector. +When a `PROCESS` is not `RUNNING` (or when the garbage collector is +running), the accumulator contents are stored in the vector, so that +the Objects they point to look like elements of the `PROCESS` and thus +are not garbage-collectible. Accumulators `A`, `B`, `C`, `D`, `E` and `O` are used almost entirely as scratch accumulators, and they are not saved or restored across -Subroutine calls. Of course the interrupt machinery always saves -these and all other accumulators. `A` and `B` are used to return a -pair as the value of a Subroutine call. Other than that special -feature, they are just like the other scratch accumulators. +Subroutine calls. Of course the interrupt machinery always saves these +and all other accumulators. `A` and `B` are used to return a pair as +the value of a Subroutine call. Other than that special feature, they +are just like the other scratch accumulators. `M` and `R` are used in running `RSUBR`s. `M` is always set up to point to the start of the `RSUBR`'s code, which is actually just a uniform vector of instructions. All jumps and other references to the code use `M` as an index register. This makes the code -location-insensitive, which is necessary because the code uvector -will move around. `R` is set up to point to the vector of objects -needed by the `RSUBR`. This accumulator is necessary because objects -in garbage-collected space can move around, but the pointers to them -in the reference vector are always at the same place relative to its +location-insensitive, which is necessary because the code uvector will +move around. `R` is set up to point to the vector of objects needed by +the `RSUBR`. This accumulator is necessary because objects in +garbage-collected space can move around, but the pointers to them in +the reference vector are always at the same place relative to its beginning. `FRM` is the internal frame pointer, used in compiled code to keep @@ -9662,9 +9654,9 @@ track of pending Subroutine calls when the control stack is heavily used. `P` is the internal-stack pointer, used primarily for internal calls in the interpreter. -One of the nicest features of the Muddle environment is the -uniformity of the calling and returning sequence. All Subroutines -- -both built-in F/SUBRs and compiled `RSUBR(-ENTRY)`s -- are called in +One of the nicest features of the Muddle environment is the uniformity +of the calling and returning sequence. All Subroutines -- both +built-in F/SUBRs and compiled `RSUBR(-ENTRY)`s -- are called in exactly the same way and return the same way. Arguments are always passed on the control stack and results always end up in the same accumulators. For efficiency reasons, a lot of internal calls within @@ -9681,9 +9673,9 @@ being called that can be called "quickly" by virtue of its having special information in its reference vector. `ACALL` ("accumulator call") is used otherwise. The general method of calling a Subroutine is to `PUSH` (a PDP-10 instruction) pairs representing the arguments -onto the control stack via `TP` and then either (1) `MCALL` or -`QCALL` or (2) put the number of arguments into an accumulator and -`ACALL`. Upon return the object returned by the Subroutine will be in +onto the control stack via `TP` and then either (1) `MCALL` or `QCALL` +or (2) put the number of arguments into an accumulator and `ACALL`. +Upon return the object returned by the Subroutine will be in accumulators `A` and `B`, and the arguments will have been `POP`ped off the control stack. @@ -9697,11 +9689,11 @@ entire state of the caller when the call occurred. The mediator then builds a new frame on the control stack and stores a pointer back to the caller's frame (the current contents of `TB`), a pointer to the Subroutine being called, and the new contents of `AB`, which is a -counting pointer to the arguments and is computed from the -information in the `MCALL` or `QCALL` instruction or the `ACALL` -accumulator. `TB` is then set up to point to the new frame, and its -left half is incremented by one, making a new `unique-id`. The -mediator then transfers control to the Subroutine. +counting pointer to the arguments and is computed from the information +in the `MCALL` or `QCALL` instruction or the `ACALL` accumulator. `TB` +is then set up to point to the new frame, and its left half is +incremented by one, making a new `unique-id`. The mediator then +transfers control to the Subroutine. A control stack frame has seven words as shown: @@ -9722,19 +9714,19 @@ A control stack frame has seven words as shown: --------------------------------- The first three words are set up during the call to the Subroutine. -The rest are filled in when this routine calls another Subroutine. -The left half of `TB` is incremented every time a Subroutine call -occurs and is used as the `unique-id` for the frame, stored in frame -and tuple pairs as mentioned before. Obviously this `id` is not -strictly unique, since each 256K calls it wraps around to zero. The -right half of `TB` is always left pointing one word past the -saved-calling-address word in the frame. `TP` is also left pointing -at that word, since that is the top of the control stack at -Subroutine entry. The arguments to the called Subroutine are below -the frame on the control stack (at lower storage addresses), and the -temporaries for the called Subroutine are above the frame (at higher -storage addresses). These arguments and temporaries are just pairs -stored on the control stack while needed: they are all that remain of +The rest are filled in when this routine calls another Subroutine. The +left half of `TB` is incremented every time a Subroutine call occurs +and is used as the `unique-id` for the frame, stored in frame and +tuple pairs as mentioned before. Obviously this `id` is not strictly +unique, since each 256K calls it wraps around to zero. The right half +of `TB` is always left pointing one word past the +saved-calling-address word in the frame. `TP` is also left pointing at +that word, since that is the top of the control stack at Subroutine +entry. The arguments to the called Subroutine are below the frame on +the control stack (at lower storage addresses), and the temporaries +for the called Subroutine are above the frame (at higher storage +addresses). These arguments and temporaries are just pairs stored on +the control stack while needed: they are all that remain of `UNSPECIAL` values in compiled programs. The following figure shows what the control stack might look like @@ -9779,18 +9771,18 @@ control stack (the "execution path"), so that it is easy to return to the caller of a given Subroutine (`ERRET` or `RETRY`). Subroutine exit is accomplished simply by the call mediator, which -loads the right half of `TB` from the previous frame pointer, -restores the "binding pointer", `P`, and `TP`, and transfers control -back to the instruction following the saved calling address. +loads the right half of `TB` from the previous frame pointer, restores +the "binding pointer", `P`, and `TP`, and transfers control back to +the instruction following the saved calling address. Variable Bindings ----------------- -All local `ATOM` values are kept on the control stack of the -`PROCESS` to which they are local. As described before, the atom -contains a word that points to the value on the control stack. The -pointer is actually to a six-word "binding block" on the control -stack. Binding blocks have the following format: +All local `ATOM` values are kept on the control stack of the `PROCESS` +to which they are local. As described before, the atom contains a word +that points to the value on the control stack. The pointer is actually +to a six-word "binding block" on the control stack. Binding blocks +have the following format: --------------------------------- | BIND or UBIND | prev | @@ -9808,18 +9800,18 @@ stack. Binding blocks have the following format: where: -- `BIND` means this is a binding for a `SPECIAL` `ATOM` (the only +- `BIND` means this is a binding for a `SPECIAL` `ATOM` (the only kind used by compiled programs), and `UBIND` means this is a binding for an `UNSPECIAL` `ATOM` -- for `SPECIAL` checking by the interpreter; -- `prev` points to the closest previous binding block for any `ATOM` +- `prev` points to the closest previous binding block for any `ATOM` (the "access path" -- `UNWIND` objects are also linked in this chain); - `decl` points to a `DECL` associated with this value, for `SET(LOC)` to check; - `unique-id` is used for validation of this block; and -- `previous-binding` points to the closest previous binding for - this `ATOM` (used in unbinding). +- `previous-binding` points to the closest previous binding for this + `ATOM` (used in unbinding). Bindings are generated by an internal subroutine called `SPECBIND` (name comes from `SPECIAL`). The caller to `SPECBIND` `PUSH`es @@ -9841,30 +9833,28 @@ restoring old value pointers in atoms until the "binding pointer" is equal to the one saved in the frame. Obviously variable binding is more complicated than this, because -`ATOM`s can have both local and global values and even different -local values in different `PROCESS`es. The solution to all of these +`ATOM`s can have both local and global values and even different local +values in different `PROCESS`es. The solution to all of these additional problems lies in the `bindid` field of the atom. Each `PROCESS` vector also contains a current `bindid`. Whenever an ATOM's local value is desired, the `RUNNING` `PROCESS`'s `bindid` is checked -against that of the atom: if they are the same, the atom points to -the current value; if not, the current `PROCESS`'s control stack must -be searched to find a binding block for this `ATOM`. This binding -scheme might be called "shallow binding". The searching is -facilitated by having all binding blocks linked together. Accessing -global variables is accomplished in a similar way, using a `VECTOR` -that is referred to as the "global stack". The global stack has only -an `ATOM` and a value slot for each variable, since global values -never get rebound. +against that of the atom: if they are the same, the atom points to the +current value; if not, the current `PROCESS`'s control stack must be +searched to find a binding block for this `ATOM`. This binding scheme +might be called "shallow binding". The searching is facilitated by +having all binding blocks linked together. Accessing global variables +is accomplished in a similar way, using a `VECTOR` that is referred to +as the "global stack". The global stack has only an `ATOM` and a value +slot for each variable, since global values never get rebound. `EVAL` with respect to a different environment causes some additional problems. Whenever this kind of `EVAL` is done, a brand new `bindid` -is generated, forcing all current local value cells of atoms to -appear invalid. Local values must now be obtained by searching the -control stack, which is inefficient compared to just pulling them out -of the atoms. (The greatest inefficiency occurs when an `ATOM`'s -`LVAL` is never accessed twice in a row in the same environment.) A -special block is built on the control stack and linked into the -binding-block chain. This block is called a "skip block" or -"environment splice", and it diverts the "access path" to the new -environment, causing searches to become relative to this new -environment. \ No newline at end of file +is generated, forcing all current local value cells of atoms to appear +invalid. Local values must now be obtained by searching the control +stack, which is inefficient compared to just pulling them out of the +atoms. (The greatest inefficiency occurs when an `ATOM`'s `LVAL` is +never accessed twice in a row in the same environment.) A special +block is built on the control stack and linked into the binding-block +chain. This block is called a "skip block" or "environment splice", +and it diverts the "access path" to the new environment, causing +searches to become relative to this new environment.