home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / sharew / exoten / rec / rec3.hlp < prev    next >
Encoding:
Text File  |  1990-10-30  |  59.5 KB  |  1,265 lines

  1. Ch. 3. PDL, Part I (numbers, 'α', "ß", L, m, n, R, T, =, |, %, @σ)
  2. Ch. 3. PDL, Part II (numbers, +, -, *, /, N, ~, ^, d, %, \, O, #, &)
  3. Ch. 3. PDL, Part III (&, p, l, G, g, u, y, v, S, c, s, P, r, $, H, !, ?, h)
  4. Ch. 3. PDL, Part IV (t, W, i, o)
  5. :    Chapter 3.  The Pushdown List (Part I, Basic PDL operations)
  6.  
  7. The pushdown list (PDL) in REC is the principal medium for argument 
  8. transmission among subroutines and operators.  Three pointers, called px, py 
  9. and pz, are associated with it.  The value of px is always the starting 
  10. address of the last argument to come onto the PDL,  py points to the next 
  11. free location in the PDL (and thus py-px is the length of the top argument) 
  12. and pz points to the current end of the PDL (since both ends of the PDL may 
  13. be used to store arguments, pz is thus the stack pointer for the upper stack 
  14. or PDL complement).  In addition, there are markers on both ends to prevent 
  15. the excess removal of operands on either end.  Since the PDL accepts 
  16. arguments of varying lengths, as soon as a new operand is to be pushed onto 
  17. the list either a pointer or a length (depending on the specific 
  18. implementation) is stored with the previous top argument so that it can be 
  19. recovered once the new argument has been disposed of.
  20.  
  21.     This figure shows schematically the PDL when empty. 
  22.  
  23.    ┌─┬────────────────────────────────────────────────────────────┬─┐
  24.    │░│                                  │▒│
  25.    └─┴────────────────────────────────────────────────────────────┴─┘
  26.       └ px, py                                pz ┘
  27.  
  28. This figure shows the PDL after a few arguments have been stored at both ends.
  29.  
  30.     α ┐ ┌ ß      ┌ δ                        ├─ l ─┤  
  31.    ┌─┬─┬───────┬─┬───┬─┬────────┬─────────────────────────┬─┬─────┬─┐
  32.    │░│α│       │ß│   │δ│    │              │l│      │▒│
  33.    └─┴─┴───────┴─┴───┴─┴────────┴─────────────────────────┴─┴─────┴─┘
  34.              px    ┘     └ py            pz ┘
  35.  
  36.  
  37.     The greek letters in the figure denote addresses; the letter l 
  38. denotes a length; these occupy two bytes.  (In the MC68000 version of REC, 
  39. lengths, rather than addresses, are used.)  The top argument is delimited by 
  40. px and py; initially these pointers delimit a null string.  The shaded cells 
  41. at either end denote markers preventing excessive erasures from the PDL.  In 
  42. figure 1(b), there are three arguments (starting at addresses ß, δ and px) on 
  43. the lower (or normal) end of the PDL; there is one argument (of length l) 
  44. stored at the upper (or complementary) end of the PDL.
  45.  
  46.     The first REC operators we will need are those that load a constant 
  47. from the program onto the PDL, delete an argument, and move it from one end 
  48. of the PDL to the other.
  49.  
  50.  
  51. Operator/Predicate        Function performed
  52.  
  53.       number    Operator, enters the number in its binary form into the PDL. 
  54.         For the time being, we will consider "number" to be a string 
  55.         of ASCII decimal digits not starting with 0 (except for an 
  56.         isolated 0) or a minus sign followed by a nonzero digit, 
  57.         followed by zero or more digits.  With these restrictions, 
  58.         the number loaded will be the two-byte binary representation 
  59.         of the corresponding decimal constant (modulo 2^16=65536); 
  60.         negative numbers are entered in two's complement form.  We 
  61.         will generalize the acceptable number forms in the next 
  62.         section.  The order in which the least and most significant 
  63.         bytes are placed on the PDL depends on the processor; on the 
  64.         Intel processors the least significant byte is stored at the 
  65.         lowest address (px), while on the Motorola MC68000 the 
  66.         reverse applies.
  67.  
  68.   'α' or "α"    Operator, places the string α of ASCII characters on the PDL. 
  69.         α may contain nests of quoted strings such that the 
  70.         delimiting quotes alternate between " and '. The null 
  71.         string may be entered into the PDL with '' or "".  
  72.         Other examples follow:
  73.  
  74.   'α' or "α" (cont.)        "quoted string"
  75.                 'another quoted string'
  76.                 'nested "quoted 'string'"'
  77.                 "another 'nested "quoted" string'"
  78.  
  79.         The nesting feature prevents the characters ' and " to be 
  80.         quoted singly; a single instance of them may be placed on the 
  81.         pushdown list by "''"% and '""'%, respectively.
  82.         Control characters such as carriage returns and line feeds 
  83.         are included in quoted strings if the opening quote appears 
  84.         on one line and the closing quote on another, but this 
  85.         depends on how files are structured in a particular operating 
  86.         system; for instance, Unix uses a single line feed to denote 
  87.         the end of a line, whereas both CR and LF are stored in CP/M 
  88.         and MS-DOS text files.  Control characters are best 
  89.         introduced by stating their numeric value and restricting to 
  90.         one byte if necessary.  For example, 26% is a two-operator 
  91.         sequence leaving a single control-Z character on the PDL; 
  92.         2573 leaves a two-character string consisting of the control 
  93.         characters for carriage return and line feed.
  94.  
  95.  
  96.  
  97.     L    Operator, removes the last entry from the PDL. If it is    
  98.         already empty, the error is noted and execution continues.
  99.         
  100.     m    Operator, moves the argument at the top of the PDL to the 
  101.         complementary PDL and writes the size (in bytes) of the 
  102.         argument moved in the two bytes just below its new location; 
  103.         pz is updated to reflect the new high limit of available PDL 
  104.         space.  The error flag is set and a null string is moved if 
  105.         the normal end of the PDL is empty.
  106.  
  107.     n    Operator, retrieves the last argument moved to the 
  108.         complementary PDL, making it the new top argument on the low 
  109.         or normal end of the PDL.  An error is indicated in the 
  110.         error flag if the complementary PDL is empty, but a null 
  111.         string is nevertheless placed on top of the normal PDL.
  112.  
  113.     The following sequence of figures shows the successive states of the 
  114. PDL as each of the operators in the REC program 
  115.  
  116.             ('abc' 2573 'def' m L n;) 
  117.  
  118. is executed, starting with an empty PDL.  
  119.  
  120.     In these figures, the tick marks represent byte boundaries, which are 
  121. omitted for the pointer and length cells.
  122.  
  123.    ┌─┬────────────────────────────────────────────────────────────┬─┐
  124.    │░│                                  │▒│
  125.    └─┴────────────────────────────────────────────────────────────┴─┘
  126.       └ px, py                                pz ┘
  127.     α ┐
  128.    ┌─┬─┬─┬─┬─┬────────────────────────────────────────────────────┬─┐
  129.    │░│α│a b c│                               │▒│
  130.    └─┴─┴─┴─┴─┴────────────────────────────────────────────────────┴─┘
  131.      px    ┘     └ py                        pz ┘
  132.     α ┐ ┌ ß
  133.    ┌─┬─┬─┬─┬─┬─┬──┬──┬────────────────────────────────────────────┬─┐
  134.    │░│α│a b c│ß│CR LF│                          │▒│
  135.    └─┴─┴─┴─┴─┴─┴──┴──┴────────────────────────────────────────────┴─┘
  136.          px    ┘     └ py                    pz ┘
  137.     α ┐ ┌ ß    ┌ δ
  138.    ┌─┬─┬─┬─┬─┬─┬──┬──┬─┬─┬─┬─┬────────────────────────────────────┬─┐
  139.    │░│α│a b c│ß│CR LF│δ│d e f│                      │▒│
  140.    └─┴─┴─┴─┴─┴─┴──┴──┴─┴─┴─┴─┴────────────────────────────────────┴─┘
  141.              px ┘     └ py                pz ┘
  142.  
  143.     α ┐ ┌ ß
  144.    ┌─┬─┬─┬─┬─┬─┬──┬──┬────────────────────────────────────┬─┬─┬─┬─┬─┐
  145.    │░│α│a b c│ß│CR LF│                      │3│d e f│▒│
  146.    └─┴─┴─┴─┴─┴─┴──┴──┴────────────────────────────────────┴─┴─┴─┴─┴─┘
  147.          px    ┘     └ py                pz ┘
  148.     α ┐
  149.    ┌─┬─┬─┬─┬─┬────────────────────────────────────────────┬─┬─┬─┬─┬─┐
  150.    │░│α│a b c│                          │3│d e f│▒│
  151.    └─┴─┴─┴─┴─┴────────────────────────────────────────────┴─┴─┴─┴─┴─┘
  152.      px ┘     └ py                    pz ┘
  153.     α ┐ ┌ ß
  154.    ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬────────────────────────────────────────────┬─┐
  155.    │░│α│a b c│ß│d e f│                          │▒│
  156.    └─┴─┴─┴─┴─┴─┴─┴─┴─┴────────────────────────────────────────────┴─┘
  157.          px    ┘     └ py                    pz ┘
  158.  
  159.  
  160.     Since REC expressions are executed from left to right, operators 
  161. creating operands on the PDL must be written before those operators which 
  162. use the operands.  This is the postfix or reverse Polish notation, which 
  163. dispenses with parentheses as grouping symbols.  We will have more to say 
  164. about this when we address the arithmetic operators.
  165.  
  166.     The next thing to consider is communications between the program and 
  167. the user.  At the simplest level, a program must be able to accept input 
  168. from the console and display output on it.  Given an operator to read single 
  169. characters from the console keyboard, we will also be needing a predicate to 
  170. determine whether a given character arrived on the PDL.  Here are two more 
  171. operators and a predicate:
  172.  
  173. Operator/Predicate        Function performed
  174.  
  175.     R    Operator, reads a character from the keyboard into the top 
  176.         of the PDL.  It also provides a convenient way to introduce 
  177.         a pause into a program by use of the combination RL, as R 
  178.         will wait until a key is pressed if a character is not 
  179.         already waiting to be read.  Notice that R does not echo to 
  180.         the console the character it reads.
  181.  
  182.     T    Operator, types on the console the contents of the top of 
  183.         the PDL, leftmost (lowest-addressed) byte first; its 
  184.         argument would normally be an ASCII character string.  It 
  185.         leaves its argument unchanged.
  186.  
  187.  
  188.  
  189.     =    Predicate, true if the last two entries on the PDL have the 
  190.         same length and are composed of the same sequence of bytes.  
  191.         The last entry is lifted regardless of the outcome of the 
  192.         comparison, the next-to-last entry will be lifted only if 
  193.         equality is established.  Note that since length is 
  194.         important, pure numerical equality doesn't yield a true 
  195.         result if the arguments are numerical data of different types 
  196.         (e.g. integer/floating point, single/double precision, 
  197.         short/long integer, etc.)
  198.  
  199.  
  200.     We can now write a program which reads characters from the keyboard 
  201. and echoes them until an asterisk is read:
  202.  
  203.             (R '*'=; T L:)
  204.  
  205. Notice the L following the T: since T does not modify the PDL, we must get 
  206. rid of each character lest the PDL saturate.  The terminating asterisk is 
  207. not echoed, and both the asterisk read by R and the one loaded on the PDL by 
  208. the operator '*' get erased by the comparison predicate.
  209.  
  210.  
  211.  
  212.     If we now want to assemble a string from characters received through 
  213. the use of R, we will be needing an operator that joins the characters 
  214. into a single string.  We will now be using subroutines, so we also give at 
  215. this point a full description of the subroutine-calling predicate @.
  216.  
  217. Operator/Predicate        Function performed
  218.  
  219.     |    Operator, concatenates the next-to-last argument with the 
  220.         last argument, forming a new argument which replaces both. 
  221.  
  222.     %    Operator, converts the top argument to the next lower type. 
  223.         For our present purposes, given a two-byte argument as the 
  224.         top of the PDL, % replaces it with its least significant 
  225.         byte: for instance 2573% leaves a single byte whose value is 
  226.         the ASCII carriage return (13 decimal).
  227.  
  228.     @σ    Predicate which causes execution of the subroutine whose name 
  229.         is the ASCII character σ.  If σ is the character @, this 
  230.         predicate uses the top PDL argument, which should be one or 
  231.         two bytes long, corresponding to the name or address, 
  232.         respectively, of the subroutine whose execution is desired.  
  233.  
  234.  
  235.   @σ (cont.)    If the subroutine called by this predicate has NOT been 
  236.         defined in REC, it will return as though it were a false 
  237.         predicate, so that (@@) should be used in this case.  @@ 
  238.         lifts its argument from the PDL before starting execution of 
  239.         the subroutine it invokes.  (In the MC68000 version, 
  240.         addresses must be 4-byte operands.)
  241.         
  242.     Let us now write a few programs which put together a line typed in 
  243. at the keyboard, with various editing options.  The simplest one is the 
  244. following:
  245.  
  246.         [read string iteratively]
  247.         {(R 13 % =; T |:) J
  248.          (''@J 2573 TL TL;)}
  249.  
  250. The main program places a null string on the PDL and calls subroutine J, 
  251. which reads, types and concatenates each incoming character to the previous 
  252. top of the PDL, until it reads a carriage return character, which causes a 
  253. return to the main program.  The main program then types a carriage return, a 
  254. line feed and the string of characters collected by subroutine J; arguments 
  255. are lifted after being typed and the program terminates.
  256.  
  257.  
  258.     We can also state the above procedure recursively:
  259.  
  260.         [read string recursively]
  261.         {(R 13 % =; T @J |;) J
  262.          (''@J 2573 TL TL;)}
  263.  
  264.         [read string recursively - another version]
  265.         {(R 13 % = ''; T @J |;) J
  266.          (@J 2573 TL TL;)}
  267.  
  268. The two versions differ in subroutine J: the second one is entirely self 
  269. contained in that it provides the null string necessary to have n+1 operands 
  270. available for the n concatenations [|] which will occur when n characters 
  271. followed by a carriage return are read; the subroutine in the first version 
  272. relies on the calling program to provide this null string.
  273.  
  274.     All three of the above programs allow no mistakes to be made during 
  275. typing.  All characters preceding the CR are concatenated into the final 
  276. string.  The simplest feature to add is backspacing to erase individual 
  277. characters.  The recursive version is more appropriate for the addition of 
  278. line editing features because the concatenation of the individual bytes is 
  279. postponed until after the CR has been read.
  280.  
  281. Our next program allows erasure of the rightmost exposed character by using 
  282. the backspace:
  283.  
  284.     [BACKSPACE to erase character and reposition cursor]
  285.     {(R 8% = 8%; 13%=''; T @J 8% = L 8%T ' 'TL TL: |;) J
  286.      (@J 8% =: 2573 TL TL;)}
  287.  
  288. When a backspace is typed, subroutine J will lift the rightmost character 
  289. from the PDL and backspace, overwrite with a blank and backspace again on its 
  290. copy on the screen (performed by the sequence 8% = L 8%T ' 'TL TL); it will 
  291. return a backspace if a backspace is given as the first character or if more 
  292. backspaces are given in succession than the number of characters collected so 
  293. far on the PDL.  The main program repeats the attempt to read a line if it 
  294. receives a backspace on return from J.
  295.  
  296.     The following program is a variant of the above, except that it uses 
  297. the rubout character "DEL" and echoes the rubbed out characters in reverse.  
  298. This version would be useful on a hardcopy terminal, where backspacing and 
  299. overprinting is impractical.
  300.  
  301.     [DEL to erase a character with echo]
  302.     {(R127%=127%;13%='';T@J127%=TL:|;) J  (@J 127%=: 2573TLTL;)}
  303.  
  304.     Another editing option is cancellation of the entire set of 
  305. characters collected so far; the following two programs allow this by use of 
  306. the ASCII control characters NAK (control-U) and CAN (control-X) which we 
  307. denote by ^U and ^X. The first program, on detection of ^U, lifts one by one 
  308. all characters gathered, types the character #, repositions the cursor or 
  309. print mechanism of the console to the beginning of the next line and resumes 
  310. the reading of a line from the beginning.  The second program blanks out the 
  311. characters written so far, returning the cursor or print mechanism to the 
  312. beginning of the same line, lifting characters from the PDL as it backspaces. 
  313. This second program will of course be better suited to a screen-type console, 
  314. whereas the first one will be more appropriate for use with a hard-copy 
  315. terminal.  In both programs the line-gathering process terminates when a 
  316. carriage return is typed at the console; the resulting line is then typed out 
  317. on a new line.
  318.  
  319.     [^U to redo a line from the beginning]
  320.     {(R 21% = 21%; 13% = ''; T @J 21% = L 21%; |;) J
  321.      (@J 21% = '#' TL 2573 TL: 2573 TL TL;)}
  322.  
  323.     [^X to cancel a line - with rubouts]
  324.     {(R 24% = 24%; 13% = ''; T @J 24% = 8% T' ' TL TL 24%; |;) J
  325.      (@J 24% =: 2573 TL TL;)}
  326.  
  327.     Yet another editing option is the capability to retype the characters 
  328. gathered so far.  Our next two programs accomplish this, in iterative and 
  329. recursive fashions, respectively.  Both type a number sign # on detection of 
  330. control-R (whose decimal value is 18) and move all characters gathered so far 
  331. to the complementary PDL, in order to type them out from the earliest 
  332. character typed in to the latest, returning them to the low PDL in the 
  333. process.  In the recursive version this is done by the sequence m@RnT in 
  334. subroutine R; in the iterative version it is done by ''m(''=;m:) ''(n''=;T:). 
  335. Both programs require an initial null string on the PDL which is used as a 
  336. marker to signal the end of the iteration of (''=;m:) in the first program 
  337. and of the recursion in the second program; this null string is removed from 
  338. the PDL by the last L in the main program.
  339.  
  340.     [^R to retype a line - iterative version]
  341.     {(R 18% = 18%; 13%= ''; T
  342.       (@J 18% = '#' TL 2573TL ''m (''=; m:) ''(n''=; T:) :;) |;) J
  343.      ('' (@J 18%=: 2573 TL TL L;);)}
  344.  
  345.     [^R to retype a line - recursive version]
  346.     {('' = '#' TL 2573TL ''; m @R n T;) R
  347.      (R 18% = 18%; 13% = ''; T (@J 18% = @R:;) |;) J
  348.      ('' (@J 18% =: 2573 TL TL L;);)}
  349.  
  350.     As a final example of line editing, we present a program which 
  351. incorporates the backspace, control-X and control-R editing options:
  352.  
  353.     [combine backspace, ^X and ^R]
  354.     {(''= '#'TL 2573TL ''; m @R n T;) R
  355.      (R    18%= 18%;        [ctrl-R]
  356.         24%= 24%;        [ctrl-X]
  357.         8%=  8%;        [BS]
  358.         13%= '';        [CR]
  359.         T(@J18%= @R:;)
  360.             8%=  L 8%T ' 'TL TL:
  361.             24%= L 8%T ' 'TL TL 24%;
  362.             |;) J
  363.      (''(@J 18%=: 24%=: 8%=: 2573TL TL L;);)}
  364.  
  365. The main program may be replaced by a subroutine L such as
  366.  
  367.      (2573TL'> 'TL''(@J 18%=:24%=:8%=: &L;);) L
  368.  
  369. and incorporated into other programs; a call @L would then prompt the user
  370. for a string, read it from the keyboard and return it as top of the PDL.
  371.  
  372. :    The Pushdown List, Part II (arithmetic operations)
  373.  
  374. All arithmetic operations in REC are carried out on operands which must be 
  375. present on the PDL, so that to evaluate an arithmetic expression we must use 
  376. reverse Polish notation to express the corresponding formula in terms of REC 
  377. operators.  Consider for example the following formula:
  378.  
  379.             π (3.5²  - 2.5²)
  380.  
  381. The first thing we can do is enter π into the PDL, but the product will have 
  382. to be postponed until the value of the parenthesized expression becomes 
  383. available.  Thus we enter 3.5 twice into the PDL and multiply (thus obtaining 
  384. the square).  Again an operation (subtraction) must be postponed until the 
  385. square of 2.5 is on the PDL.  Accordingly we enter 2.5 twice into the PDL and 
  386. multiply.  At this point there are three arguments on the PDL: 6.25, 12.25 
  387. and π (starting from the top).  We may now subtract 6.25 from 12.25 and 
  388. multiply π and the difference together.  The sequence of REC operators is the 
  389. following:
  390.  
  391.             3.1415926 3.5 3.5 * 2.5 2.5 * - *
  392.  
  393.  
  394.  
  395.     Since each arithmetic operator requires a known and fixed number of 
  396. arguments, no grouping symbols (such as the parentheses used in the original 
  397. formula) are needed; in our example, each of the operators * and - uses the 
  398. last two arguments entered into the PDL and leaves a single result. An 
  399. alternative sequence of operators to produce the same result would be
  400.  
  401.             3.5 3.5 * 2.5 2.5 * - 3.1415926 *
  402.  
  403. which has the advantage of minimizing the number of arguments present on the 
  404. PDL at any given point.  In this formulation, however, one must take care 
  405. that at least one space or comma separates the subtraction operator from the 
  406. number-loading operator 3.1415926, for otherwise the dash would be compiled 
  407. as part of the constant following it, rather than as the subtraction operator.
  408.  
  409.     We continue now our discussion of operators which take their arguments
  410. from the PDL with a description of the arithmetic/logical operators.  A 
  411. feature common to the operators +, - and * is that they require two arguments 
  412. and return one result in place of the original two. The operator / returns 
  413. two values if both arguments are of numeric types whose size doesn't exceed 4 
  414. and one if at least one of them is of floating point type (size 5 or 8).  If 
  415. arguments of different sizes are given to +, -, *, / or the predicate N, 
  416. conversions of the argument of smaller size to larger sizes will occur until 
  417. the sizes match, and then the operation will be performed. 
  418. If the top argument is not a numeric type (size 0, 1, 2, 4, 5 or 8), the 
  419. error flag is set, the operation is abandoned and the PDL remains unchanged.  
  420. If the top argument is of numeric type but the next is not, the operation 
  421. will be abandoned after setting the error flag and the top argument is lost, 
  422. as it is removed from the PDL before testing the next argument and is not 
  423. replaced in case of error.
  424.  
  425.     All arithmetic and logical operations are restricted to 1 and 2-byte 
  426. integers in the case of REC80 and REC86, which do not incorporate long 
  427. integers and floating point numbers, nor automatic type conversions for
  428. operands of different sizes.
  429.  
  430. Operator/Predicate        Function performed
  431.  
  432.       number    Operator, enters the number in its binary form into the PDL. 
  433.         "number"  may be an instance of any of the following 
  434.         expressions, where in addition to the metasymbols introduced 
  435.         in Chapter 1, d is any decimal digit (0-9), n is a nonzero 
  436.         decimal digit (1-9) and ε stands for the null string:
  437.  
  438.             Two-byte integers:
  439.  
  440.                 -n | d | [-|ε]nd*
  441.   number (cont.)
  442.             Four-byte integers:
  443.  
  444.                 [-0|0d]d*
  445.  
  446.             Single precision floating point numbers:
  447.  
  448.                 [-|ε]d*.d*  |
  449.                 [-|ε]d*.d*E[-|+|ε]d*  |
  450.                 [-|ε]dd*E[-|+|ε]d*
  451.  
  452.             Double precision floating point numbers:
  453.  
  454.                 [-|ε]d*.d*D[+|-|ε]d*  |
  455.                 [-|ε]dd*D[+|-|ε]d*
  456.         
  457.         The terms "two-byte", "four-byte", "single" and "double 
  458.         precision" refer to the internal representation of the 
  459.         numbers, which require 2, 4, 5 and 8 bytes, respectively. 
  460.         Note that all forms may be preceded by an optional minus 
  461.         sign, but not by a plus sign, which would be interpreted as 
  462.         the addition operator.  
  463.  
  464.   number (cont.)    Expressed in words, the above forms mean the following, 
  465.         apart from the optional sign:  A two-byte integer is any 
  466.         single digit, a string of digits whose first digit is not 
  467.         zero or a minus sign followed by a string of digits the first 
  468.         of which is not 0; a four byte integer is -0 or a string of 
  469.         two or more digits the first of which is always zero.  A 
  470.         single precision (SP) floating point number is signaled by 
  471.         the presence of a period (indicating the decimal point), the 
  472.         letter E followed by an optionally signed digit string, or 
  473.         both, except that if the decimal point is not present, at 
  474.         least one digit must appear for the E to be interpreted as 
  475.         part of a number.  A double precision (DP) floating point 
  476.         number always has the letter D followed by an optionally 
  477.         signed and possibly empty digit string; again, in the absence 
  478.         of a period at least one digit to the left of the D is 
  479.         required for the presence of a numeric constant to be 
  480.         recognized. The number on the right of the E or D (whose 
  481.         value is zero if the digit string is empty) is interpreted as 
  482.         a power of ten which multiplies the number represented by the 
  483.         digit string on its left. 
  484.         
  485.         The following panel shows a few examples. 
  486.         
  487.   number (cont.)
  488.             0        Two-byte integer zero.
  489.             00        Four-byte integer zero.
  490.             -127        Two-byte number.
  491.             01000001    Four-byte number.
  492.             .        Single precision 0.
  493.             .1E-15        Single precision number.
  494.             4D200        Double precision number.
  495.             3.14159265358D    Double precision number.
  496.             -E3        Not a number, but three    operators: 
  497.                     -,  E and the two-byte integer 3.
  498.  
  499.         The syntax of floating point numbers is mostly identical to 
  500.         that of FORTRAN's REAL and DOUBLE PRECISION constants, the 
  501.         exceptions being that an initial + is not part of the number, 
  502.         that the period by itself yields a valid number (0) and that 
  503.         the digit string in the exponent may be empty.  Finally, the 
  504.         syntax allows no blanks or other characters within the string 
  505.         defining a constant; any character not allowed by the above 
  506.         possibilities terminates the conversion and compilation of 
  507.         the number and is preserved and compiled as the next operator 
  508.         or predicate in the program.
  509.  
  510.     +    Operator.  If either argument is the null string, the result 
  511.         is the other argument; a null remains if both are null.  If 
  512.         both arguments are one byte long, + returns the logical sum 
  513.         (or) of its arguments (i.e., a bit of the result is 1 if 
  514.         either of the corresponding bits in the arguments is 1, 0 if 
  515.         both are 0). If either argument is of size 2 or greater, the 
  516.         result will be the arithmetic sum of the two arguments 
  517.         expressed in the type of the larger of the two arguments.
  518.  
  519.     -    Operator.  If the top argument is the null string, the 
  520.         result is the other argument; if the lower argument is null, 
  521.         the top argument is returned if its size is 1 and its 
  522.         negative otherwise.  If both arguments are 1 byte items the 
  523.         result will be their logical exclusive or (in which a given 
  524.         bit of the result is 1 if the corresponding bits of the 
  525.         arguments are different, 0 otherwise); for arguments of 
  526.         larger sizes this operator returns the result of subtracting 
  527.         the top argument from the next (e.g., 3.,5- yields -2.).
  528.  
  529.     *    Operator.  Returns a zero of the size of the longer argument 
  530.         if the other argument is the null string, a null string if 
  531.         both are null.  
  532.         
  533.   * (cont.)    If the size of both arguments is 1, the result is the logical 
  534.         product (and) of the operands (the result will have a one 
  535.         only where the corresponding bits of the original arguments 
  536.         are one).  All other cases result in the arithmetic product 
  537.         of the operands performed and expressed in the type of the 
  538.         longer operand.
  539.  
  540.     /    Operator.  Returns two zeros of the size of the top argument 
  541.         if the lower one is the null string; in all other cases it 
  542.         attempts to divide the lower argument by the top.  Two one- 
  543.         byte arguments always yield two-byte results; integer 
  544.         divisions leave two results, the remainder and the quotient 
  545.         (with the quotient as top argument) whereas floating point 
  546.         divisions leave only the quotient.  Two-byte integers are 
  547.         considered unsigned, so that -1,2/ yields 32767 as the 
  548.         quotient and 1 as the remainder, because -1 is treated 
  549.         as 65535.  The results of four byte integer divisions, on 
  550.         the other hand, reflect the signs of the operands.  Integer 
  551.         division by zero leaves the arguments unchanged (except for 
  552.         one-byte operands which will have been converted to two-byte 
  553.         integers); floating-point division by zero returns the 
  554.         largest representable number of the corresponding type.
  555.  
  556.     N    Predicate. It requires two arguments, both of which are 
  557.         lifted regardless of the logical outcome.  If both arguments 
  558.         are null, N is true.  Otherwise, conversions are performed on 
  559.         the smaller argument if the sizes are different; size one 
  560.         operands make N true if their logical product is nonzero and 
  561.         false otherwise; N is true for other sizes if the lower 
  562.         argument is less than or equal to the top argument and false 
  563.         otherwise.  (Note that two-byte integers are treated as 
  564.         unsigned operands in the comparison.)
  565.  
  566.     ~    Operator, requires one numeric argument.  Leaves null strings 
  567.         unchanged, complements or negates its argument if its size is 
  568.         one or greater than one, respectively.  The error flag is set 
  569.         and the operation is abandoned if the argument is nonnumeric.
  570.  
  571.     ^    Operator.  Mostly used to increment the top argument by one. 
  572.         The top argument must be of a valid numeric operand size; 
  573.         null strings are left unchanged.  In practice, ^ places a 1 
  574.         of the size of its operand on the PDL and uses the + 
  575.         operator to complete its action.
  576.  
  577.  
  578.  
  579.     d    Predicate.  Requires one numeric argument.  If d's argument 
  580.         is the null string or a zero of any size, it gets lifted and 
  581.         the truth value of the predicate is false.  Otherwise d 
  582.         subtracts the value 1 of the appropriate size from its 
  583.         operand and returns with the value true.
  584.  
  585.  
  586.     %    Operator, converts the top argument to the next lower type, 
  587.         where the order, from greater on down is double precision/ 
  588.         single precision/four-byte integer/two-byte integer/ one-byte 
  589.         argument/null string.  Arguments whose size is not 0, 1, 2, 
  590.         4, 5 or 8 remain unchanged and cause an error to be noted.  
  591.         DP to SP and SP to 4-byte integer conversions may cause 
  592.         overflow, indicated by the largest number representable in 
  593.         the corresponding format.  Integer to integer conversions are 
  594.         always done by removal of the appropriate number of 
  595.         high-order bytes. Null strings are left unchanged.  This 
  596.         operator is often used to generate single ASCII control 
  597.         characters.  For instance, a single carriage return may be 
  598.         generated by the two-operator sequence 13%.
  599.  
  600.  
  601.  
  602.     \    Operator, converts the top argument to the next higher type; 
  603.         see the above description of % for the ordering of operand 
  604.         types.  \ is also restricted to numeric types.  Conversion of 
  605.         an integer type to another integer type is accomplished by 
  606.         appending the appropriate number of zero bytes on the left, 
  607.         with no sign extension (one and two-byte numbers are treated 
  608.         as unsigned integers); conversion of long integer to single 
  609.         precision floating point does take the sign of the integer 
  610.         into account.  Double precision operands are left unchanged.
  611.  
  612.     O    Predicate.  True if the argument on the PDL is an ASCII 
  613.         string satisfying the syntax of numbers given above; the 
  614.         result is the same number converted to the corresponding 
  615.         binary representation.  Both the null string and a single 
  616.         minus sign are accepted and convert to a two-byte zero.  O 
  617.         is false if termination of the number conversion algorithm 
  618.         doesn't occur at the end of the argument, in which case the 
  619.         argument is left unchanged.
  620.  
  621.  
  622.  
  623.  
  624.  
  625.     #    Operator.  Converts a numeric argument to a decimal ASCII 
  626.         string representation of the argument's value.  The null 
  627.         string always yields a single ASCII 0, results from 
  628.         four-byte integers always contain an extra leading 0, 
  629.         single-precision floating point operands always produce a 
  630.         string containing a decimal point and double-precision 
  631.         arguments always produce a decimal point and a D-prefixed 
  632.         exponent of ten in their result.  Nonnumeric arguments cause 
  633.         the error flag to be set and the operation to be abandoned 
  634.         with no changes to the PDL.
  635.  
  636.     &    Operator, exchanges the top two arguments, regardless of 
  637.         their sizes.  The arguments need not be numeric.
  638.  
  639.     pG    A combination of the operators p and G (to be described in 
  640.         detail later on) whose effect is to place on the PDL a 
  641.         duplicate of the top argument.
  642.  
  643.     lyG    A combination of the operators l, y and G (described 
  644.         individually in the next section); the net effect is to place 
  645.         on the PDL a copy of the last operand moved to the PDL 
  646.         complement without affecting it.  This combination is 
  647.         equivalent to npGm, but it involves less byte movements. 
  648.  
  649.     Let us illustrate the use of the operators and predicates just 
  650. described with a few examples.  In our first example a recursive factorial 
  651. subroutine is driven by its main program to produce factorials for the 
  652. integers 0 to 12 in four-byte arithmetic.  Subroutine F expects one 
  653. argument on the PDL and replaces it with a single result.
  654.  
  655.     [4-byte factorial of an integer, defined as follows:
  656.      n! = n*(n-1)! for n>0;       0! = 1]
  657.        { [recursive factorial subroutine]
  658.      (pG -01 N 'Error' TL; 00 = 01; pG d @F *;) F
  659.  
  660.      [main program: loop until PDL top becomes 013]
  661.      (00 (013 =; pG # T O '!=' TL @F # TL 2573TL ^:) ;) }
  662.  
  663.     Note that the factorial subroutine only gives valid results for 
  664. input values between 0 and 12 (since 13! is greater than 2 147 483 647, the 
  665. largest positive integer representable in the four-byte format), and that it 
  666. rejects negative values of its argument.
  667.  
  668.  
  669.  
  670.  
  671.     Our second program uses Newton's method for roots of equations to 
  672. extract the square root of a non-negative numbers.
  673.  
  674.     [Square root by Newton's method]
  675.        { [collect a string from the console, with editing options]
  676.      (''='#'TL@c''; m@RnT;) R
  677.      (R18%=18%; 24%=24%; 8%=8%; 13%='';
  678.       T(@J18%=@R:;) 8%=L8%T' 'TLTL: 24%=L8%T' 'TLTL24%; |;) J
  679.  
  680.      [prompt for input, deliver the input string]
  681.      ('>'TL''(@J 18%=: 24%=: 8%=: @c&L;);) L
  682.      [type carriage return and line feed]     (2573TL;) c
  683.  
  684.      [Newton iteration routine: requires the number c whose 
  685.       root is sought to be on the complementary PDL and an 
  686.       approximation x to the root on the PDL]
  687.      (pG pG lyG & / + 0.5 *          [yields new approx. (x+(c/x))/2.]
  688.       pG m -    [save approx. and compute difference with previous]
  689.       (pG 0. N ~;;)        [make absolute value of the difference]
  690.       lyG /             [compute error relative to new approx]
  691.       1.E-8 N n;      [exit if relative error below this threshold]
  692.       n pG # TL @c:) N    [type current approximation and repeat]
  693.  
  694.      [Main program: get input, check validity, get root]
  695.      (@L (O)L 'Not a number' TL @c:
  696.       0.+ \%    [force argument to single precision floating point]
  697.       pG 0. N L;               [exit if input is 0 or negative]
  698.       pG m @N                 [set up arguments, call N]
  699.       'sqrt('TL n #TL ')='TL #TL @c:) }      [type result, repeat]
  700.  
  701.     This program illustrates the use of parentheses to negate a 
  702. predicate [(O) in the first line of the main program], in this case to 
  703. reject input strings that do not translate to a numeric value.  In the second 
  704. line of the main program, 0.+ ensures that integer arguments of whatever 
  705. size get converted to the single precision floating point formats; the pair 
  706. \% ensures that double precision arguments get reduced to single precision, 
  707. while leaving single precision values unchanged.  The program is terminated 
  708. if a nonpositive argument was given; otherwise the arguments for N are set 
  709. up, N is called, the result is displayed and the program repeats from the 
  710. beginning.  N is called with the number itself as the initial approximation; 
  711. we will show how to improve this in the next section.
  712.  
  713.  
  714.  
  715.  
  716.  
  717.     Subroutine N is a more extensive example of reverse Polish notation 
  718. usage.  Given an approximation x to the root on the PDL and the number c 
  719. whose root is sought on the PDL complement, the sequence pGpGnpGm& leaves the 
  720. set of operands [x, x, c, x] on the PDL (listed from deepest to topmost) and 
  721. c on the PDL complement; the operators /, +, 0.5 and * leave successively the 
  722. operands [x, x, c/x], [x, x+(c/x)], [x, x+(c/x), 0.5] and [x, 0.5*(x+(c/x))] 
  723. on the PDL.  The last result is the new approximation obtained by application 
  724. of Newton's formula; let us call it x'.  The relative error │x-x'│/2 is 
  725. computed, and if it does not exceed 1E-8, x' is returned as the final result, 
  726. with c remaining in the PDL complement; otherwise the value of x' is typed 
  727. and a new iteration is carried out.
  728.  
  729.     In our final example of this section we give a subroutine to compute 
  730. the double precision cosine of its argument, assumed to be given in radians, 
  731. by means of a range reduction to the interval [0,π/2] and a Taylor series 
  732. expansion through the 10th term:
  733.  
  734.       9      k   2k
  735.  cos x ≈  Σ  (-1)   x  /(2k)! = (1 - (x²/2)(1 - (x²/12)(1 - (x²/30)(1 -
  736.      k=0
  737.                 (x²/56)(1 - (x²/90)(1 - (x²/132)(1 -
  738.  
  739.                 (x²/182)(1 - (x²/240)(1 - (x²/306))))))))))
  740.     [cosine, using range reduction and a Taylor series expansion]
  741.     {(0.D0 +         [make sure argument is double precision]
  742.       (pG 0.D0 N ~;;)    [take absolute value [cos(-x)=cos x]]
  743.       pG 1.5707963267948966D0 / 0.5D0 +           [get x/(pi/2)]
  744.       (pG 2147483648D0 N; 'Out of range'TLL)    [check range]
  745.       %%            [floor of x/(pi/2): n = |_x/(pi/2)_|]
  746.       pG 04/Lm\\             [save mod(n,4), convert n to DP]
  747.       1.5707963267948966D0 pGm * -    [x - n*pi/2: range reduction]
  748.       n lyG 02/L (00=L;L& -;)  [reverse interval if mod(n,4) odd]
  749.       pG * ~ pG m            [ -x*x, a copy on the complement]
  750.       306.D/^ lyG240.D/*^ lyG182.D/*^      [inner three terms]
  751.       lyG132.D/*^ lyG90.D/*^ lyG56.D/*^       [next three terms]
  752.       lyG30.D/*^ lyG12.D/*^ n2.D/*^           [last three terms]
  753.       n (d 01N ~;;)         [give proper sign according to mod(n,4)]
  754.       ;;) c
  755.  
  756.      [main program: call c to make a table]
  757.       (00 (025=; pG 015*       [do table in 15 degree increments]  
  758.         \\pG#TL              [convert to DP, type value]
  759.         3.1415926535897932D0 * 180D0/     [convert to radians]
  760.         @c '  'TL #TL 2573TL    [compute cosine, type result]
  761.         ^:)                   [increment and repeat]
  762.        ;) }
  763. : The Pushdown List, Part III (Address handling, data movement and variables)
  764.  
  765. Since one of the purposes of REC is that it should be a language in which 
  766. operating system functions can be conveniently expressed, it is clear that it 
  767. should have a set of operators to move data between the PDL and anywhere in 
  768. memory, and that it should allow creating blocks on the PDL itself for use as 
  769. buffers.  Once blocks are created, a means for storing their addresses must 
  770. be provided.  This role is filled by variables, which is an array where 
  771. addresses (or address-sized data) may be stored.
  772.  
  773.     A word on addresses before going on to the list of operators.  In 
  774. REC80 (the REC compiler for the 8080 and compatible processors like the 8085 
  775. and Z80) all addresses are two byte integers.  In the compiler for the 8086 
  776. processor (REC86), addresses may be two- or four-byte operands; if an address 
  777. is a two-byte integer, it is assumed to be an offset relative to the data 
  778. segment base.  The data segment contains the buffers for communicating with 
  779. the operating system (CP/M-86 or MS-DOS), the variable and subroutine address 
  780. tables, and the PDL.  A four-byte argument given as an address in REC86 is 
  781. assumed to consist of a segment base (the upper two bytes) and an offset (the 
  782. lower two bytes) relative to that base, allowing thus access to the entire 
  783. address space of the 8086.  In REC68, the compiler for the MC68000, all 
  784. addresses must be given as four-byte integers; conversely, operators 
  785. producing addresses yield four-byte integers.
  786.     In both REC80 and REC86 the table of variables is an array of 
  787. two-byte cells; storing a four-byte 8086 address in a variable will occupy 
  788. the given variable and the one following.  In REC68 the variable cells are 
  789. four bytes long.
  790.  
  791.     In addition to the address, variable and block operations, we 
  792. include in our next list operators and predicates to effect hexadecimal 
  793. conversions, to test for the occurrence of errors and to save and restore 
  794. the machine registers.
  795.  
  796. Operator/Predicate        Function performed
  797.         
  798.     &    Operator.  & exchanges the top two PDL arguments, regardless 
  799.         of their sizes.
  800.         
  801.     p    Operator, places the two 2-byte values px and py-px on the 
  802.         PDL; that is, the origin and the size of the top argument.
  803.         In REC68, the origin is a four-byte value.
  804.  
  805.     l    Operator. Places on the PDL the value of pz, which is the 
  806.         current high limit of the PDL as well as the address of the 
  807.         cell containing the size of the last argument entered by the 
  808.         operator m on the complementary PDL.
  809.     G    Operator.  Requires two 2-byte values on the PDL, an origin 
  810.         (lower) and a value n representing a size (top).  It 
  811.         replaces both with an argument of n bytes copied from the n 
  812.         locations starting at the given origin.  Thus pG duplicates 
  813.         the top argument and 128pGG gets the 128 bytes starting 
  814.         at address 128 (absolute on the 8085; data segment relative 
  815.         on the 8086).
  816.  
  817.     g    Operator.  Given an address as the top argument, it fetches 
  818.         the byte stored at that address and places it on the PDL.  
  819.         The address is not removed, but remains as the lower 
  820.         argument.
  821.  
  822.     u    Operator.  Identical to g except that it increments by one 
  823.         the address operand after fetching the byte stored at the 
  824.         given address. Only the offset in the lower two bytes is 
  825.         incremented when a 4-byte address is given in the 8086 
  826.         version.
  827.  
  828.     y    Operator.  Similar to u, but a word (two bytes) is fetched 
  829.         and the address is incremented by two.  The same provisions 
  830.         apply regarding 4-byte arguments in the 8086 version.
  831.  
  832.     v    Operator.  Given two arguments on the PDL, an address 
  833.         (lower) and a datum (top), it stores the datum forward from 
  834.         the designated memory location, erases it, and adds the size 
  835.         of the datum to the address, which remains on the PDL.  
  836.         Only the offset is modified when a four-byte address is
  837.         given in the 8086 version of REC.
  838.  
  839.     S    Operator. Expects two arguments on the PDL, a datum (lower) 
  840.         and an address (top).  It stores the datum forward from the 
  841.         designated memory location and erases both arguments from 
  842.         the PDL when done.  
  843.  
  844.     c    Operator.  Given a 2-byte integer n on the PDL, c creates in 
  845.         its place a block of n bytes and leaves as top argument a 
  846.         pointer to the beginning of this block (a two-byte address). 
  847.         If n is 2 or larger, the value n-2 is stored in the first 
  848.         two bytes of the block, a useful arrangement if the block is 
  849.         to be used as a buffer by s or P; no other initialization is 
  850.         made.
  851.  
  852.  
  853.  
  854.  
  855.     s    Operator, stores into an area of limited size. Requires two 
  856.         arguments, a datum (lower) and an address (top).  If the 
  857.         address is α, s will store the datum beginning at α+2 if its 
  858.         size does not exceed the value stored at the word pointed to 
  859.         by α (notice the connection with operator c above); no data 
  860.         is stored at all if all will not fit and the error flag will 
  861.         be set in this case.  Both arguments are lifted if the datum 
  862.         fits; the datum will remain if it does not fit.
  863.  
  864.     P    Operator, stores into a buffer and notes length.  Similar in 
  865.         arguments and operation to s.  The size of the datum will be 
  866.         stored at the word whose address is α+2 and the datum 
  867.         itself will be stored starting at α+4 if it will fit, that 
  868.         is, if its size plus 2 does not exceed the buffer size stored 
  869.         at the word pointed to by α.  Both arguments are lifted if 
  870.         the data fits, but only the address will be lifted if it 
  871.         does not.  The error flag is set in the latter case.  
  872.  
  873.     r    Operator.  Given an address as top argument, r replaces it 
  874.         by the two-byte value at which it points.  In REC68, the 
  875.         result is the four-byte word contained at the given address.
  876.  
  877.  
  878.     $    Operator. Given a one- or two-byte argument on the PDL, whose 
  879.         value lies between 0 and 127, $ replaces it with the address 
  880.         of the corresponding cell in the table of variables and 
  881.         subroutines.  Values between 0 and 32, and the value 127 are 
  882.         used as variables, as they correspond to ASCII control 
  883.         characters and are thus never used as subroutine names. 
  884.         Values between 33 and 126 correspond to cells containing the 
  885.         current definitions of REC subroutines whose names are the 
  886.         corresponding ASCII characters.  Since @ and } are also 
  887.         excluded as subroutine names, their cells may be used for 
  888.         storing other addresses.
  889.  
  890.     H    Predicate.  True if the top argument is a hexadecimal string 
  891.         in ASCII (containing only the decimal digits 0-9 and the 
  892.         letters A-F), in which case it is converted to binary.  
  893.         Conversion of an n-digit string produces an |_(n+1)/2_|-byte 
  894.         value stored according to the processor's convention (least 
  895.         significant byte in the lowest-addressed location in the 
  896.         Intel processors; most significant byte in the lowest-
  897.         addressed location on the 68000); |_x_| is the greatest 
  898.         integer not exceeding x.  
  899.  
  900.  
  901.   H (cont.)    Notice that leading zeros in the string affect the size of 
  902.         the result.  Arguments causing H to become false are left 
  903.         unchanged.  The null string causes H to be true, but is left 
  904.         unchanged.
  905.  
  906.     !    Operator.  Performs the conversion inverse to H.  Given an n 
  907.         byte value on the PDL (assumed to be stored following the 
  908.         appropriate convention) it produces the corresponding 2n 
  909.         character hexadecimal string in ASCII (with leading zeros if 
  910.         necessary).
  911.  
  912.     ?    Predicate.  False if no error has been recorded in the error 
  913.         flag, true if a notation exists.  In the latter case, the 
  914.         value of the flag is placed on the PDL.  This value is the 
  915.         address of the last location from which the error notation 
  916.         routine was called. No indication is given as to how many 
  917.         errors have occurred if this predicate is true.  The error 
  918.         flag is reset after being consulted.
  919.  
  920.  
  921.  
  922.  
  923.  
  924.     h    Operator.  Stores, restores or eliminates stored machine 
  925.         registers.  It requires a single null argument, an argument 
  926.         consisting of a pointer to the machine stack or two 
  927.         arguments, the lower one a pointer to the stack an the top 
  928.         one a two-byte zero.  The first use of h must provide a 
  929.         single null string.  On the 8080, this causes h to push onto 
  930.         the stack the registers PSW, HL, DE and  BC, leaving the 
  931.         value of the machine's stack pointer SP (which points to the 
  932.         last of the stacked values) in place of the null argument. If 
  933.         h is given a non-zero two-byte argument, it assumes it is the 
  934.         value of SP pointing to the location on the machine stack at 
  935.         which it stored previously the machine registers, which it 
  936.         then proceeds to unstack, leaving out of reach anything else 
  937.         which may have been stacked after the corresponding ''h call; 
  938.         it lifts also the SP value given on the PDL.  If the top 
  939.         argument is a two-byte zero, h will assume that an SP value 
  940.         is the next argument, and uses it to restore SP to the value 
  941.         prior to the first use of ''h, that is, it lifts the stacked 
  942.         register values from the machine stack without restoring 
  943.         them; it also lifts both given arguments from REC's PDL.  On 
  944.         the 8086, the stack pointer argument is a 4-byte value 
  945.         consisting of the SP value in the lower two bytes and the 
  946.         Stack Segment base in the upper two bytes.  
  947.    h (cont.)    The registers saved are the flags, AX, BX, CX, DX, BP, SI, 
  948.         DI, DS and ES.  On the 68000, the SP argument is the address 
  949.         value of register A7; the flags and all registers but A7 are 
  950.         saved.  Since PDL and workspace pointers are kept in machine 
  951.         registers in REC68, much care must be exercised in using this 
  952.         operator.  In all versions, a store/restore or 
  953.         store/eliminate operation pair must occur within the same 
  954.         expression; otherwise other stack contents (notably return 
  955.         addresses and entry points saved by braces) will be lost.
  956.  
  957.     The main operators for saving and fetching data are G and S.  The 
  958. remainder were especially chosen on the one hand to scrutinize the memory 
  959. under REC control, and on the other to give the widest possible latitude in 
  960. defining variables in applications of REC.
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967.  
  968.  
  969.  
  970.     The following list shows a few ways to use the above operators; in 
  971. it α, ß and δ represent any operations generating addresses, µ represents 
  972. a two-byte constant, Θ represents a variable number (0-32, 127) and 'data' 
  973. represents any operation producing on the PDL a datum to be stored.
  974.  
  975.     α(ß=;g[process]v:)    process bytewise from α to ß-1
  976.  
  977.     ßα(δ=L;u[proc]&mvn:)    fetch string from α to δ-1, process 
  978.                 bytewise, save at ß and following
  979.  
  980.     αµm(ndm pGr[proc]v:L;)    process µ words starting at α
  981.  
  982.     α Θ $S            store address α in variable cell Θ
  983.  
  984.     Θ $r            fetch contents of variable cell Θ
  985.  
  986.     'data' m l Θ $S        store datum in PDL complement, save its
  987.                 address in variable Θ
  988.  
  989.     Θ $r yG            retrieve datum from PDL complement (other 
  990.                 items may have been moved to the PDL 
  991.                 complement meanwhile, making the datum not 
  992.                 immediately available to n)
  993.  
  994.     'data' Θ $r s        use PDL complement block as buffer, redefine 
  995.                 its contents
  996.  
  997.     µ c Θ $S        create a (µ-2)-byte buffer on the PDL, save 
  998.                 its address in variable Θ
  999.  
  1000.     µ cL m l Θ$S        create a µ-byte buffered variable on the 
  1001.                 PDL complement
  1002.  
  1003.     'data' Θ $r s        write into a buffer (length not noted)
  1004.  
  1005.     'data' Θ $r P        write into a buffer (length noted)
  1006.  
  1007.     Θ $r^^yG        recover datum saved by P
  1008.  
  1009.     Θ $r yG            retrieve entire contents of a buffer
  1010.  
  1011.     To make our next examples interesting and useful, we will have them 
  1012. handle the information received by the program through the operating system's 
  1013. "command line".  This will require explaining some operating system internals;
  1014. we will restrict our discussion to CP/M and MS-DOS.
  1015.  
  1016.     In CP/M and MS-DOS, a program residing on a disk is called into 
  1017. execution by means of a "command line", consisting of the program name 
  1018. followed by a space and any parameters that the program is to receive.  This 
  1019. parameter string or "command line tail" is passed on to the program in the 
  1020. buffer starting at address 080H (hexadecimal); address 080H contains the 
  1021. character count of the string and the string is stored forward from address 
  1022. 081H.  The first two parameters of the command line tail are parsed as file 
  1023. names and placed forward from locations 05CH and 06CH.  A file name consists 
  1024. of a disk identifier, a name of up to 8 characters and an extension of up to 
  1025. 3 characters; omission of the disk designator causes a default of @ (which 
  1026. indicates the currently logged disk unit) before conversion to the internal 
  1027. disk-numbering scheme, the other two parts are blank filled on the right.  If 
  1028. the command line tail is empty, the file name buffer at 5CH is certain to 
  1029. contain eleven blanks starting at 05DH.
  1030.  
  1031.     When REC is called into execution and finds a file name at 05CH, it 
  1032. will attempt to open it, and read, compile and execute a program from it.  
  1033. Any parameters following this file name are treated as a command line tail to 
  1034. be received by the REC program at the beginning of its execution.
  1035.  
  1036.  
  1037.  
  1038.  
  1039.         rec80 sample file.one b:file.two
  1040.  
  1041. The above command line causes the program from file SAMPLE.REC to be compiled 
  1042. and executed; this compiled program will have available to it the file name 
  1043. FILE.ONE expanded and stored in the buffer at 5CH, the file name B:FILE.TWO 
  1044. expanded and stored in the buffer at 6CH and the command line tail "FILE.ONE 
  1045. B:FILE.TWO" starting at 81H with the character count (19) in location 80H.  
  1046. The program from file SAMPLE may access this information through the 
  1047. operators given above, as illustrated in the following examples.
  1048.  
  1049.     [make a buffer in which to save the second file name
  1050.      and save it; type and return the buffer's address]
  1051.     (33 c pG '05D'H 12G & S ! T H;) M
  1052.  
  1053. In this example, 33c creates a 33-byte buffer and its address; the pG which 
  1054. follows makes a copy of the address to be used later by the operator S; 
  1055. '05D'H12G copies the 12-byte expanded file name to the PDL, & exchanges data 
  1056. and address for S and S stores the 12 data bytes starting at the beginning of 
  1057. the 33-byte buffer. !TH converts the address to ASCII, types it and restores 
  1058. is to binary.  The reason behind making a longer buffer is that CP/M requires 
  1059. a "file control block" (FCB) for its operation on disk files; prior to 
  1060. opening a file the last 21 bytes of the FCB should be 0.
  1061.  
  1062.     One way of initializing the rest of an FCB is illustrated by the next 
  1063. subroutine:
  1064.  
  1065.     [clear the upper 21 bytes of an FCB, given its
  1066.      address; leave the original address]
  1067.     (pG 12 + 7m (n d m '000000'H v:;)L;) C
  1068.  
  1069.     This subroutine uses pG to ensure a copy of the original address is 
  1070. left on the PDL upon completion.  12+ adds 12 to the address, which is the 
  1071. starting location to be cleared. 7m sets up a counter in the PDL, and a loop 
  1072. starts.  The sequence n d m fetches the counter, decrements it and returns it 
  1073. to the PDL complement (if not zero), '000000'H makes a three-byte binary zero 
  1074. and v stores it forward from the current address, which it updates (adding 
  1075. three to it in this case) after storing.  Notice that d in the inner loop 
  1076. will be true 7 times so that v will store the 21 required zeros.  The final L 
  1077. erases the address left over from the last execution of v.
  1078.  
  1079.     We may use variable cells to store FCB addresses for later use by 
  1080. the operating system call operators k and K (treated in Chapter 5):
  1081.  
  1082.     [calls M and C above to make FCBs for the filenames at 05CH and 06CH;
  1083.      the FCB addresses are saved in variables 30 and 31, respectively]
  1084.     ('05C'H @M @C 30$S '06C'H @M @C 31$S;) F
  1085.  
  1086. The following subroutines illustrate the use of operators g and u.
  1087.  
  1088.     [Returns the address of the first nonblank character between
  1089.      two addresses, searching from highest to lowest]
  1090.     (& m (g (" "=) nL; (d) n; pG n & =; m:) ;) <
  1091.  
  1092.     [Similar to the previous routine, searching from lowest to
  1093.      highest]
  1094.     (m (u (" "=) dnL; pG n & =; m:) ;) >
  1095.  
  1096. In both subroutines the top PDL argument is assumed to be the higher address; 
  1097. the argument next to the top should be the lower address.  In the first 
  1098. subroutine the address left by g is explicitly decremented, whereas in the 
  1099. second the operator d is used only when a nonblank character is found.  
  1100. Operator & is used before predicate = in both subroutines to retain the 
  1101. limiting address of the search (the lowest address in the first case and the 
  1102. highest in the second); recall that predicate = always erases at least the 
  1103. top argument.
  1104.  
  1105.     Finally we exhibit an example in which l, y, s, P and r are used,
  1106. in the next panel.
  1107.  
  1108. [Execution of s and P, with diagnostics]
  1109. {(N n s;) s   (2- N n P;) P    (&mm p&L n lyGr & @@; n "Datum too big" TL)} Q
  1110.  
  1111. Subroutine Q must receive three arguments:  the two required by s or P and 
  1112. the letter s or the letter P as the top argument.  The first action taken is 
  1113. to exchange the letter and the buffer address and send both to the PDL 
  1114. complement [&mm].  The length of the datum to be stored is next placed on the 
  1115. PDL and the name of the subroutine to be called is retrieved [p&Ln].  The 
  1116. combination lyG puts on the normal end of the PDL a copy of the last argument 
  1117. sent to the PDL complement, which in this case is the buffer address; r 
  1118. replaces this address with its contents, i.e., leaves on the PDL the length 
  1119. of the buffer (assuming it was created by operator c).  & exchanges this 
  1120. value with the given letter and @@ calls the subroutine whose name is that 
  1121. letter.  If the letter is s, the length of the datum is tested against the 
  1122. buffer size, and if the former is less than or equal to the latter, the 
  1123. buffer address is retrieved and the datum is stored [Nns]; if the letter is 
  1124. P, 2 is subtracted from the buffer size (since P requires two bytes from the 
  1125. buffer to store the datum's length) and a comparison is performed before 
  1126. retrieving the address and executing operator P.  If in either s or P the 
  1127. comparison turns out to be false, predicate @@ becomes false, the address is 
  1128. retrieved and an error message is sent to the console; both datum and buffer 
  1129. address remain on the PDL, but subroutine Q terminates logically false.
  1130.  
  1131.     To close this section we give an improved version of the square root 
  1132. program.  This one distinguishes single and double precision arguments 
  1133. (integer arguments are converted to single precision) and computes (in 
  1134. subroutine I) the first approximation to the square root by dividing the 
  1135. number's exponent by two.  REC uses the ANSI/IEEE Standard 754-1985 for its 
  1136. floating point format, except that single precision numbers include an extra 
  1137. mantissa byte in order to distinguish them from long integers.  The standard 
  1138. specifies different exponent lengths for the single and double precision 
  1139. formats, as illustrated in the following figures, in which field boundaries 
  1140. are indicated by solid vertical bars, byte boundaries are denoted by broken 
  1141. lines, and bits are indicated by tick marks.  The most significant byte is on 
  1142. the left.
  1143.  
  1144.         ┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
  1145.         s│   e  |│    |    |f    |    │    (a)
  1146.         └┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘
  1147.  
  1148.     ┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
  1149.     s│   e  |    │   |        |        |    f   |        |        |        │   (b)
  1150.     └┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘
  1151.  
  1152.         (a) Single precision; (b) Double precision
  1153.  
  1154.     For a non-zero, in-range argument, in both cases 0.5 ≤ f < 1; the 
  1155. value of the single precision number is (-1)^s 2^(e-127) (1+f) and the value 
  1156. of the double precision number is (-1)^s 2^(e-1023) (1+f).  Thus, a better 
  1157. first approximation to the square root of a number whose biased exponent is e 
  1158. will be a number with the same mantissa and a biased exponent ((e-b)/2)+b, 
  1159. where b is the appropriate bias.  In order to compute this, we must extract 
  1160. the most significant two bytes, separate the exponent from the highest 
  1161. mantissa bits (we don't have to worry about s, since it is 0 in this 
  1162. problem), remove the bias, divide by 2, add back the bias, and reassemble.
  1163.  
  1164.     [Square root by Newton's method]
  1165.        { [collect a string from the console, with editing options]
  1166.      (''='#'TL@c''; m@RnT;) R
  1167.      (R18%=18%; 24%=24%; 8%=8%; 13%='';
  1168.       T(@J18%=@R:;) 8%=L8%T' 'TLTL: 24%=L8%T' 'TLTL24%; |;) J
  1169.      [prompt for input, deliver the input string]
  1170.      ('>'TL''(@J 18%=: 24%=: 8%=: @c&L;);) L
  1171.      [type carriage return and line feed]     (2573TL;) c
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.      [compute initial approximation: divide exponent by 2]
  1178.      (p (8 =                      [test length]
  1179.         6+ 16pGm1023;        [expt. address & const. for DP]
  1180.         +2-,128pGm127;) pGmmm      [constants on PDL complement]
  1181.       pG2G         [repeat address, get word containing exponent]
  1182.       n/            [separate exponent from high mantissa bits]
  1183.       n-,2/ &L n+           [remove bias, divide by 2, replace bias]
  1184.       n*+ &S;) I                [reassemble word, store it]
  1185.  
  1186.      [Newton iteration routine: requires the number c whose 
  1187.       root is sought to be on the complementary PDL and an 
  1188.       approximation x to the root on the PDL]
  1189.      (pG pG lyG & / + 0.5 *          [yields new approx. (x+(c/x))/2.]
  1190.       pG m -    [save approx. and compute difference with previous]
  1191.       (pG 0. N ~;;)        [make absolute value of the difference]
  1192.       lyG /             [compute error relative to new approx]
  1193.       (p&L8= 1.D-15;L1.E-8;)     [choose appropriate threshold]
  1194.       N n;          [exit if relative error below this threshold]
  1195.       n pG # TL @c:) N    [type current approximation and repeat]
  1196.  
  1197.  
  1198.  
  1199.  
  1200.      [Main program: get input, check validity, get root]
  1201.      (@L (O)L 'Not a number' TL @c:
  1202.       0.+                 [force argument to floating point]
  1203.       pG 0. N L;               [exit if input is 0 or negative]
  1204.       pG m @I @N     [set up arguments, get initial approx, call N]
  1205.       'sqrt('TL n #TL ')='TL #TL @c:) }      [type result, repeat]
  1206.  
  1207.  
  1208.     In subroutine I, besides giving us the operand's address, p provides 
  1209. us with a means to test whether it is a single or double precision number.  
  1210. We use this again in subroutine N to choose the convergence threshold. In the 
  1211. exponent extraction and reassembly we take advantage of the fact that integer 
  1212. division leaves both quotient and remainder.  Note that the address of the 
  1213. most significant pair of bytes depends on the processor; when using REC68 we 
  1214. would have to remove the operator pair 6+ in the second line of subroutine I 
  1215. and replace +2- in the third line with the operator L, since the most 
  1216. significant word of the operand is already pointed at by px.
  1217.  
  1218. :            The Pushdown List, Part IV
  1219.  
  1220.     The last group of operators which take their arguments from the PDL 
  1221. is composed of input and output operators.
  1222.  
  1223.      Operator            Function performed
  1224.  
  1225.     t        Operator.  Given an address "org" (as top argument)
  1226.             and a length "l" (as lower argument), t displays on 
  1227.             the console the string of l characters stored in 
  1228.             memory starting at address org.  Both arguments are 
  1229.             lifted from the PDL.  Notice that T is equivalent to 
  1230.             the operator pair pt; t is often used in combination
  1231.             with q, an operator described in the next chapter.
  1232.  
  1233.     W        Operator whose arguments are identical to those
  1234.             required by t, but which sends the character string 
  1235.             described by the argument to the device logged in the 
  1236.             operating system as the list device (the LST: device 
  1237.             of CP/M; usually a printer).  W also removes both of 
  1238.             its arguments from the PDL after using them.
  1239.  
  1240.  
  1241.     i        Operator.  Given an argument on the PDL whose least
  1242.             significant byte represents the number of one of the 
  1243.             computer's communication ports, i reads in a byte 
  1244.             from that port, which it leaves on the PDL as top 
  1245.             argument.  The original argument stays on the PDL so 
  1246.             that it may be reused after disposing of the byte 
  1247.             read by i.
  1248.  
  1249.     o        Operator requiring two arguments, the lower one such
  1250.             that its least significant byte is the number of a 
  1251.             port and the top a byte to be written to that port.  
  1252.             o outputs the given byte to the indicated port and 
  1253.             lifts the byte from the PDL.  The port number stays 
  1254.             on the PDL, facilitating multiple outputs to the same 
  1255.             port.
  1256.  
  1257.     It should be clear that operators i and o afford the user detailed 
  1258. control of the peripheral resources of the computer, but for the same reason 
  1259. its use results in REC programs which are extremely dependent on the specific 
  1260. configuration of the computer for which they are written; consequently these 
  1261. two operators have not been used very frequently.
  1262.  
  1263. :[REC3.HLP]
  1264. [(c) G. Cisneros, 1985, 1990]
  1265.