home *** CD-ROM | disk | FTP | other *** search
-
-
- Chapter 3. The Pushdown List
-
- The pushdown list (PDL) in REC is the principal medium for
- argument transmission among subroutines and operators. Three pointers,
- called px, py and pz are associated with it. Px always points to the
- address on the PDL where the last argument to come in starts, py points to
- the next free location in the PDL (and thus py-px is the length of the top
- argument) and pz points to the current end of the PDL. In addition, there
- are markers on both ends to prevent the excess removal of operands on
- either end.
-
- Programming operations on the PDL requires becoming familiar
- with reverse Polish, or postfix notation, since all operands needed by
- a given operation must be present on the PDL before the operation can
- be performed and since operations are performed from left to right. It is
- well known that arithmetic expressions written in either prefix or postfix
- notation require no parentheses. Consider the following simple example:
-
- ('hello' T L;)
-
- This is a complete REC program which places the five-character
- string hello on the PDL, types it on the console and lifts it (erases it)
- from the PDL. These operations are accomplished by the operators 'hello',
- T and L, respectively. Next consider the program
-
- (3.5 pG * 2.5 pG * - 3.1415926 * # T L;)
-
- This one computes the area of a circular ring of inner radius 2.5 units
- and outer radius 3.5 units by squaring 3.5 [3.5 pG *], squaring 2.5 [2.5
- pG *] and subtracting and multiplying by pi [- 3.1415926 *]. The result
- is converted into an ASCII string by #, typed on the console by T and
- erased from the PDL by L. The combined operator pG places on the PDL a
- new copy of the current top argument and the characters * and - are the
- multiplication and subtraction operators, respectively. Notice that at
- least one blank or comma must separate the minus sign from the number that
- follows in order for it to be considered the binary subtraction operator
- rather than a unary minus sign affecting the number.
-
- Before proceeding to consider more examples of REC
- programming, we introduce in detail a few operators and predicates
- dealing only with the PDL:
-
- Operator/Predicate Function performed
-
- L Operator, removes the last entry from the
- PDL. If it's already empty, the error is
- noted and execution continues.
-
- = Predicate, true if the last two entries on the
- PDL have the same length and are composed of
- the same sequence of bytes. The last entry is
- lifted regardless of the outcome of the
- comparison, the next-to-last entry will be
- lifted only if equality is established. Note
- that since length is important, pure numerical
- equality doesn't yield a true result if the
- arguments are numerical data of different
- types (e.g. integer/floating point,
- single/double precision, short/long integer,
- etc.)
-
- number Operator, enters the number in its binary form
- into the PDL. "number" may be an instance of
- any of the following expressions, where [, ],
- * and | are the same metasymbols used in
- Chapter 1, d is any decimal digit (0-9), n is
- a nonzero decimal digit (1-9) and e stands for
- the null string:
-
- Two-byte integers:
- [-n|d]
- [-|e]n[d]*
-
- Four-byte integers:
- [-0|0d][d]*
-
- Single precision floating point numbers:
- [-|e][d]*.[d]*
- [-|e][d]*.[d]*E[-|+|e][d]*
- [-|e]d[d]*E[-|+|e][d]*
-
- Double precision floating point numbers:
- [-|e][d]*.[d]*D[+|-|e][d]*
- [-|e]d[d]*D[+|-|e][d]*
-
- The terms "two-byte", "four-byte", "single"
- and "double precision" refer to the internal
- representation of the numbers, which require
- 2, 4, 5 and 8 bytes, respectively. Note that
- all forms may be preceded by an optional
- minus sign, but not by a plus sign, which
- would be interpreted as the addition
- operator. Expressed in words, the above
- forms mean the following, apart from the
- optional sign: A two-byte integer is any
- single digit, a string of digits whose first
- digit is not zero or a minus sign followed by
- a string of digits the first of which is not
- 0; a four byte integer is -0 or a string of
- two or more digits the first of which is
- always zero. A single precision (SP)
- floating point number is signaled by the
- presence of a period (indicating the decimal
- point), the letter E followed by an
- optionally signed digit string, or both,
- except that if the decimal point is not
- present, at least one digit must appear for
- the E to be interpreted as part of a number.
- A double precision (DP) floating point number
- always has the letter D followed by an
- optionally signed and possibly empty digit
- string; again, in the absence of a period at
- least one digit to the left of the D is
- required for the presence of a numeric
- constant to be recognized. The number on
- the right of the E or D (whose value is zero
- if the digit string is empty) is interpreted
- as a power of ten which multiplies the number
- represented by the digit string on its left.
- Examples:
-
- 0 Two-byte integer zero.
- 00 Four-byte integer zero.
- -127 Two-byte number.
- 01000001 Four-byte number.
- . Single precision 0.
- .1E-15 Single precision number.
- 4D200 Double precision number.
- 3.14159265358D Double precision number.
- -E3 Not a number, but three
- operators: -, E and the
- two-byte integer 3.
-
- The syntax of floating point numbers is mostly
- identical to that of FORTRAN's REAL and DOUBLE
- PRECISION constants, the exceptions being that
- an initial + is not part of the number, that
- the period by itself yields a valid number (0)
- and that the digit string in the exponent may
- be empty. Finally, the syntax allows no blanks
- or other characters within the string defining
- a constant; any character not allowed by the
- above possibilities terminates the conversion
- and compilation of the number and is preserved
- and compiled as the next operator or predicate
- in the program.
-
- % Operator, converts the top argument to the next
- lower type, where the order, from greater on
- down is double precision/single precision/four-
- byte integer/two-byte integer/one-byte argument
- /null string. Arguments whose size is not 0,
- 1, 2, 4, 5 or 8 remain unchanged and cause an
- error to be noted. DP to SP and SP to 4-byte
- integer conversions may cause overflow,
- indicated by the largest number representable
- in the corresponding format. Integer to
- integer conversions are always done by removal
- of the appropriate number of high-order bytes.
- Null strings are left unchanged. This operator
- is often used to generate single ASCII control
- characters. For instance, a single carriage
- return may be generated by the two-operator
- sequence 13%.
-
- \ Operator, converts the top argument to the next
- higher type; see the above description of % for
- the ordering of operand types. \ is also
- restricted to numeric types. Conversion of an
- integer type to another integer type is
- accomplished by appending the appropriate
- number of zeros on the left, with no sign
- extension (one and two-byte numbers are
- treated as unsigned integers); conversion of
- long integer to single precision floating
- point does take the sign of the integer into
- account. Double precision operands are left
- unchanged.
-
- | Operator, concatenates the next-to-last
- argument with the last argument, forming a
- new argument which replaces both.
-
- R Operator, reads a character from the keyboard
- into the top of the PDL. It also provides a
- convenient way to introduce a pause into a
- program by use of the combination RL, as R
- will wait until a key is pressed if a character
- is not already waiting to be read. Notice
- that R does not echo to the console the
- character which it reads.
-
- T Operator, types on the console the contents of
- the top of the PDL, leftmost (lowest-addressed)
- byte first; its argument would normally be an
- ASCII character string. It leaves its argument
- unchanged.
-
- 'x' or "x" Operator, places the string x of ASCII
- characters on the PDL. x may contain nests of
- quoted strings such that the delimiting quotes
- alternate between " and '. The null string
- may be entered into the PDL with '' or "".
- Other examples follow:
-
- "quoted string"
- 'another quoted string'
- 'nested "quoted 'string'"'
- "another 'nested "quoted" string'"
-
- The nesting feature prevents the characters '
- and " to be quoted singly; a single instance
- of them may be placed on the pushdown list by
- "''"% and '""'%, respectively. Control
- characters such as carriage returns and line
- feeds are included in quoted strings if the
- opening quote appears on one line and the
- closing quote on another; other control
- characters are best introduced by stating
- their numeric value and restricting to one
- byte if necessary. For example, 26% leaves
- a single control-Z character on the PDL; 2573
- leaves a two-character string consisting of
- the control characters for carriage return
- and line feed.
-
- m Operator, moves the argument at the top of
- the PDL to the high end of the memory space
- defined for the PDL (which constitutes thus
- a complementary PDL) and writes the size (in
- bytes) of the argument moved in the two bytes
- just below its new location; pz is updated to
- reflect the new high limit of available PDL
- space. The error flag is set and a null
- string is moved if the normal end of the PDL
- is empty.
-
- n Operator, retrieves the last argument moved to
- the complementary PDL, making it the new top
- argument on the low or normal end of the PDL.
- An error is indicated in the error flag if the
- complementary PDL is empty, but a null string
- is nevertheless placed on top of the normal PDL.
-
- @x Predicate which causes execution of the
- subroutine whose name is the ASCII character
- x. If x is the character @, this predicate
- uses the top PDL argument, which should be one
- or two bytes long, corresponding to the name
- or address, respectively, of the subroutine
- whose execution is desired. If the subroutine
- called by this predicate has NOT been defined
- in REC, it will return as though it were a
- false predicate, so that (@@) should be used
- in this case. @@ lifts its argument from the
- PDL before starting execution of the
- subroutine it invokes.
-
- With the foregoing operators and predicates, we may now write
- a few programs which put together a line typed in at the keyboard,
- with various editing options. The simplest one is the following:
-
- [read string iteratively]
- {(R13%=;T|:) J
- (''@J 2573TLTL;)}
-
- The main program places a null string on the PDL and calls subroutine
- J (which is done by the predicate @J, as described in the previous
- chapter) which reads, types and concatenates each incoming character
- to the previous top of the PDL, until it reads a carriage return
- character, which causes a return to the main program. The main
- program then types a carriage return, a line feed and the string of
- characters collected by subroutine J; arguments are lifted after
- being typed and the program terminates.
-
- The above procedure may also be stated recursively:
-
- [read string recursively]
- {(R13%=;T@J|;) J
- (''@J 2573 TLTL;)}
-
- [read string recursively - another version]
- {(R13%='';T@J|;) J
- (@J 2573 TLTL;)}
-
- The two versions differ in that subroutine J in the second one is
- entirely self contained in that it provides the null string necessary
- to have n+1 operands available for the n concatenations | which will
- occur when n characters followed by a carriage return are read; the
- subroutine in the first version relies on the calling program to
- provide this null string.
-
- The recursive version is more appropriate for the addition of
- line editing features. Consider for example a program that allows
- for erasure of the rightmost exposed character by using the backspace:
-
- [BACKSPACE to erase character and reposition cursor]
- {(R8%=8%; 13%=''; T@J8%=L8%T' 'TLTL: |;) J
- (@J 8%=: 2573TLTL;)}
-
- When a backspace is typed, subroutine J will lift the rightmost
- character from the PDL and backspace, overwrite with a blank and
- backspace again on its copy on the screen (performed by the sequence
- 8%=L8%T' 'TLTL); it will return a backspace if a backspace is given
- as the first character or if more backspaces are given in succession
- than the number of characters collected so far on the PDL. The main
- program repeats the attempt to read a line if it receives a backspace
- on return from J.
-
- The following program is a variant of the above, except that
- it uses the rubout character "del" and echoes the rubbed out
- characters in reverse. This version would be useful on a hardcopy
- terminal, where backspacing and overprinting is impractical.
-
- [DEL to erase a character with echo]
- {(R127%=127%;13%='';T@J127%=TL:|;) J
- (@J 127%=: 2573TLTL;)}
-
- The following two programs allow for canceling any characters
- gathered so far by use of the ASCII control characters NAK
- (control-U) and CAN (control-X) which we denote by ^U and ^X. The
- first program, on detection of ^U, lifts one by one all characters
- gathered, types the character #, repositions the cursor or print
- mechanism of the console to the beginning of the next line and
- resumes the reading of a line from the beginning. The second program
- blanks out the characters written so far, returning the cursor or
- print mechanism to the beginning of the same line, lifting characters
- from the PDL as it backspaces. This second program will of course be
- better suited to a screen-type console, whereas the first one will be
- more appropriate for use with a hard-copy terminal. In both programs
- the line-gathering process terminates when a carriage return is typed
- at the console; the resulting line is then typed out on a new line.
-
- [^U to redo a line from the beginning]
- {(R21%=21%;13%='';T@J21%=L21%;|;) J
- (@J 21%='#'TL2573TL: 2573TLTL;)}
-
- [^X to cancel a line - with rubouts]
- {(R24%=24%;13%='';T@J24%=8%T' 'TLTL24%;|;) J
- (@J 24%=: 2573TLTL;)}
-
- Another editing option is the capability to retype the
- characters gathered so far. The next two programs accomplish this,
- in iterative and recursive fashions, respectively. Both type a
- number sign # on detection of control-R (whose decimal value is 18)
- and move all characters gathered so far to the complementary PDL, in
- order to type them out from the earliest character typed in to the
- latest, returning them to the low PDL in the process. In the
- recursive version this is done by the sequence m@RnT in subroutine R;
- in the iterative version it is done by ''m(''=;m:) ''(n''=;T:). Both
- programs require an initial null string on the PDL which is used as a
- marker to signal the end of the iteration of (''=;m:) in the first
- program and of the recursion in the second program; this null string
- is removed from the PDL by the last L in the main program.
-
- [^R to retype a line - iterative version]
- {(R18%=18%;13%='';T
- (@J18%='#'TL2573TL''m(''=;m:)''(n''=;T:):;)
- |;) J
- (''(@J 18%=: 2573TLTLL;);)}
-
- [^R to retype a line - recursive version]
- {(''='#'TL2573TL'';m@RnT;) R
- (R18%=18%;13%='';T(@J18%=@R:;)|;) J
- (''(@J 18%=: 2573TLTLL;);)}
-
- As a final example of line editing, we present a program
- which incorporates the backspace, control-X and control-R editing
- options:
-
- [combine backspace, ^X and ^R]
- {(''='#'TL2573TL'';m@RnT;) R
- (R18%=18%;24%=24%;8%=8%;13%='';
- T(@J18%=@R:;)
- 8%=L8%T' 'TLTL:
- 24%=L8%T' 'TLTL24%;|;) J
- (''(@J 18%=:24%=:8%=: 2573TLTLL;);)}
-
- We continue now our discussion of operators which take their
- arguments from the PDL with a description of the arithmetic/logical
- operators. A feature common to the operators +, - and * is that they
- require two arguments and return one result in place of the original
- two. The operator / returns two values if both arguments are of
- numeric types whose size doesn't exceed 4 and one if at least one of
- them is of floating point type (size 5 or 8). If arguments of
- different sizes are given to +, -, *, / or the predicate N,
- conversions of the argument of smaller size to larger sizes will
- occur until the sizes match, and then the operation will be
- performed. If the top argument is not a numeric type (size 0, 1, 2,
- 4, 5 or 8), the error flag is set, the operation is abandoned and the
- PDL remains unchanged. If the top argument is of numeric type but
- the next is not, the operation will be abandoned after setting the
- error flag and the top argument is lost, as it is removed from the
- PDL before testing the next argument and is not replaced in case of
- error.
-
- Operator/Predicate Function performed
-
- + Operator. If either argument is the null
- string, the result is the other argument; a
- null remains if both are null. If both
- arguments are one byte long, + returns the
- logical sum (or) of its arguments (i.e., a
- bit of the result is 1 if either of the
- corresponding bits in the arguments is 1, 0
- if both are 0). If either argument is of size
- 2 or greater, the result will be the
- arithmetic sum of the two arguments expressed
- in the type of the larger of the two arguments.
-
- - Operator. If the top argument is the null
- string, the result is the other argument; if
- the lower argument is null, the top argument
- is returned if its size is 1 and its negative
- otherwise. If both arguments are 1 byte
- items the result will be their logical
- exclusive or (in which a given bit of the
- result is 1 if the corresponding bits of the
- arguments are different, 0 otherwise); for
- arguments of larger sizes this operator
- returns the result of subtracting the top
- argument from the next (e.g., 3,5- yields -2).
-
- * Operator. Returns a zero of the size of the
- longer argument if the other argument is the
- null string, a null string if both are null.
- If the size of both arguments is 1, the result
- is the logical product (and) of the operands.
- All other cases result in the arithmetic
- product of the operands performed and
- expressed in the type of the longer operand.
-
- / Operator. Returns two zeros of the size of
- the top argument if the lower one is the null
- string; in all other cases it attempts to
- divide the lower argument by the top. Two one-
- byte arguments always yield two-byte results;
- integer divisions leave two results, the
- remainder and the quotient (with the quotient
- as top argument) whereas floating point
- divisions leave only the quotient. Two-byte
- operand divisions are unsigned, results of
- four byte integer divisions reflect the signs
- of the operands. Integer division by zero
- leaves the arguments unchanged (except for
- one-byte operands which will have been
- converted to two-byte integers); floating-point
- division by zero returns the largest
- representable number of the corresponding type.
-
- N Predicate. It requires two arguments, both of
- which are lifted regardless of the logical
- outcome. If both arguments are null, N is
- true. Otherwise, conversions are performed on
- the smaller argument if the sizes are
- different; size one operands make N true if
- their logical product is nonzero and false
- otherwise; N is true for other sizes if the
- lower argument is less than or equal to the
- top argument and false otherwise. (Note that
- two-byte integers are treated as unsigned
- operands in the comparison.)
-
- ~ Operator, requires one numeric argument.
- Leaves null strings unchanged, complements or
- negates its argument if its size is one or
- greater than one, respectively. The error
- flag is set and the operation is abandoned if
- the argument is non numeric.
-
- ^ Operator. Mostly used to increment the top
- argument by one. The top argument must be of
- a valid numeric operand size; null strings are
- left unchanged. ^ places a 1 of the size of
- its operand on the PDL and uses the + operator
- to complete its operation.
-
- d Predicate. Requires one numeric argument. If
- d's argument is the null string or a zero of
- any size, it gets lifted and the truth value
- of the predicate is false. Otherwise d
- subtracts the value 1 of the appropriate size
- from its operand and returns with the value
- true.
-
- O Predicate. True if the argument on the PDL is
- an ASCII string satisfying the syntax of
- numbers given above; the result is the same
- number converted to the corresponding binary
- representation. Both the null string and a
- single minus sign are accepted and convert to
- a two-byte zero. O is false if termination of
- the number conversion algorithm doesn't occur
- at the end of the argument, in which case the
- argument is left unchanged.
-
- # Operator. Converts a numeric argument to a
- decimal ASCII string representation of the
- argument's value. The null string always
- yields a single ASCII 0, results from
- four-byte integers always contain an extra
- leading 0, single-precision floating point
- operands always produce a string containing a
- decimal point and double-precision arguments
- always produce a decimal point and a D-prefixed
- exponent of ten in their result. Nonnumeric
- arguments cause the error flag to be set and
- the operation to be abandoned with no changes
- to the PDL.
-
- & Operator, exchanges the top two arguments,
- regardless of their sizes.
-
- pG A combination of the operators p and G (to be
- described in detail later on) whose effect is
- to place on the PDL a duplicate of the top
- argument.
-
- Two examples will illustrate the use of the operators and
- predicates just described. In the first example a recursive
- factorial subroutine is driven by its main program to produce
- factorials for the integers 0 to 12 in four-byte arithmetic; in the
- second, Newton's method for roots of equations is applied to the
- problem of extracting the square root of a non-negative number.
-
-
- [4-byte factorial of an integer, defined as follows:
- n! = n*(n-1)! for n>0
- 0! = 1 ]
- {(pG-01N'Error'TL;00=01;pGd@F*;) F
- (00 (013=;pG#TO'!='TL@F#TL2573TL^:);)}
-
-
- [Square root by Newton's method]
- {
- [collect a string from the console, with editing options]
- (''='#'TL@c'';m@RnT;) R
- (R18%=18%; 24%=24%; 8%=8%; 13%='';
- T(@J18%=@R:;) 8%=L8%T' 'TLTL: 24%=L8%T' 'TLTL24%; |;) J
-
- [prompt for input, deliver the input string]
- ('>'TL''(@J 18%=: 24%=: 8%=: @c&L;);) L
-
- [type carriage return and line feed]
- (2573TL;) c
-
- [Newton iteration routine: requires the number C whose
- root is sought to be on the complementary PDL and an
- approximation X to the root on the PDL]
- (pGpGnpGm & / + 0.5 * [yields new approx. (X+(C/X))/2.]
- pGm - [save approx. and compute difference with previous]
- (pG0.N~;;) [make absolute value of the difference]
- npGm/ [compute error relative to new approx]
- 1.E-8Nn; [exit if rel. err. below this threshold]
- npG#TL@c:) N [type current approximation and repeat]
-
- [Main program: get input, check validity, get root]
- (@L (O)L 'Not a number'TL@c:
- 0.+ [force argument to floating point]
- pG0.NL; [exit if input is 0 or negative]
- pGm@N [set up arguments, call N]
- 'sqrt('TLn#TL')='TL#TL@c:) } [type result, repeat]
-
-
- Items to be noted about the factorial subroutine are that it
- only gives valid results for input values between 0 and 12 (since 13!
- is greater than 2 147 483 647, the largest positive integer
- representable in the four-byte format), and that it rejects negative
- values of its argument. The square root program illustrates the use
- of parenthesis to negate a predicate [(O) in the first line of the
- main program], in this case used to reject input strings that don't
- translate to a numeric value.
-
- Subroutine N of the square root program shows how reverse
- Polish notation is used to express arithmetic operations. Given that
- the approximation X to the root is on the PDL and that the number C
- whose root is sought is on the PDL complement, the sequence pGpGnpGm&
- leaves the set of operands [X, X, C, X] on the PDL (listed from
- deepest to topmost) and C on the PDL complement; the operators /, +,
- 0.5 and * leave successively the operands [X, X, C/X], [X, X+(C/X)],
- [X, X+(C/X), 0.5] and [X, 0.5*(X+(C/X))] on the PDL. The last result
- is the new approximation obtained by application of Newton's formula.
-
- The last set of PDL operators and predicates concerns mostly
- the movement of data and the manipulation of addresses. These
- operators and predicates are the following:
-
- Operator/Predicate Function performed
-
- H Predicate. True if the top argument is a
- hexadecimal string in ASCII (containing only
- the decimal digits 0-9 and the letters A-F),
- in which case it is converted to binary.
- Conversion of an n-digit string produces an
- |_(n+1)/2_|-byte value stored in Intel
- convention (least significant byte in the
- lowest-addressed location); |_x_| is the
- greatest integer not exceeding x. Notice
- that leading zeros in the string affect the
- size of the result. Arguments causing H to
- become false are left unchanged. The null
- string causes H to be true, but is left
- unchanged.
-
- ! Operator. Performs the conversion inverse to
- H. Given an n byte value on the PDL (assumed
- to be stored following Intel convention) it
- produces the corresponding 2n character
- hexadecimal string in ASCII (with leading
- zeros if necessary).
-
- p Operator, places the two 2-byte values px and
- py-px on the PDL; that is, the origin and the
- size of the top argument.
-
- l Operator. Places on the PDL the value of pz,
- which is the current high limit of the PDL as
- well as the address of the cell containing the
- size of the last argument entered by the
- operator m on the complementary PDL.
-
- c Operator. Given a 2-byte integer n on the
- PDL, c creates in its place a block of n
- bytes and leaves as top argument a pointer
- to the beginning of this block (a two-byte
- address). If n is 2 or larger, the value
- n-2 is stored in the first two bytes of the
- block, an arrangement useful if the block is
- to be used as a buffer; no other initialization
- is made.
-
- G Operator. Requires two 2-byte values on the
- PDL, an origin (lower) and a value n
- representing a size (top). It replaces both
- with an argument of n bytes copied from the n
- locations starting at the given origin. Thus
- pG duplicates the top argument and '080'HpGG
- gets the 128 bytes starting at address 128
- (absolute on the 8085; data segment relative
- on the 8086). On the 8086 the origin may be a
- four-byte value, in which case the lower bytes
- contain the address of the block to move and
- the higher two bytes contain the segment base
- of the block, allowing thus access to the
- entire address space of the 8086.
-
- g Operator. Given an address as the top
- argument, it fetches the byte stored at that
- address and places it on the PDL. The
- address is not removed, but remains as the
- lower argument. Four-byte addresses are
- allowed in the 8086 version, as described
- above in connection with G.
-
- u Operator. Identical to g except that it
- increments by one the address operand after
- fetching the byte stored at the given address.
- Only the address in the lower two bytes is
- incremented when a 4-byte address is given
- in the 8086 version.
-
- y Operator. Similar to u, but a word (two
- bytes) is fetched and the address is
- incremented by two. The same provisions
- apply regarding 4-byte arguments in the 8086
- version.
-
- S Operator. Expects two arguments on the PDL, a
- datum (lower) and an address (top). It stores
- the datum forward from the designated memory
- location and erases both arguments from the
- PDL when done. The address argument may be a
- 4-byte item in the 8086 version, as described
- above under G.
-
- v Operator. Given two arguments on the PDL, an
- address (lower) and a datum (top), it stores
- the datum forward from the designated memory
- location, erases it, and adds the size of the
- datum to the address, which remains on the
- PDL. Four-byte items are allowed as addresses
- in the 8086 version.
-
- s Operator, stores into an area of limited size.
- Requires two arguments, a datum (lower) and an
- address (top). If the address is 'org', s
- will store the datum beginning at org+2 if its
- size does not exceed the value stored at the
- word pointed to by org (notice the connection
- with operator c above); no data is stored at
- all if all will not fit and the error flag
- will be set in this case. In either event
- both arguments are lifted. As with the
- preceding operators, the address may be a
- four-byte item in the 8086 version of REC.
-
- P Operator, stores into a buffer and notes
- length. Similar in arguments and operation to
- s. The size of the datum will be stored at
- the word whose address is org+2 and the datum
- itself will be stored starting at org+4 if it
- will fit, that is, if its size plus 2 doesn't
- exceed the buffer size stored at the word
- pointed to by org. Both arguments are lifted
- if the data fits, but only the address will be
- lifted if it does not. The error flag is set
- in the latter case. Four-byte addresses are
- also allowed in the 8086 version.
-
- r Operator. Given an address as top argument, r
- replaces it by the two-byte value at which it
- points. Four-byte addresses composed of an
- address in the lower two bytes and a segment
- base in the upper two bytes are allowed by the
- 8086 version.
-
- h Operator. Stores, restores or eliminates
- stored machine registers. It requires a
- single null argument, an argument consisting
- of a pointer to the machine stack or two
- arguments, the lower one a pointer to the
- stack an the top one a two-byte zero. The
- first use of h must provide a single null
- string, whereby h pushes onto the stack of the
- 8085 the registers PSW, HL, DE and BC,
- leaving the value of the machine's stack
- pointer SP (which points to the last of the
- stacked values) in place of the null argument.
- If h is given a non-zero two-byte argument, it
- assumes it is the value of SP pointing to the
- location on the machine stack at which it
- stored previously the machine registers, which
- it then proceeds to unstack, leaving out of
- reach anything else which may have been
- stacked after the corresponding ''h call; it
- lifts also the SP value given on the PDL. If
- the top argument is a two-byte zero, h will
- assume that an SP value is the next argument,
- and uses it to restore SP to the value prior
- to the first use of ''h, that is, it lifts
- the stacked register values from the machine
- stack without restoring them; it also lifts
- both given arguments from REC's PDL. On the
- 8086, the stack pointer argument is a 4-byte
- value consisting of the SP value in the lower
- two bytes and the Stack Segment base in the
- upper two bytes. The registers saved are the
- flags, AX, BX, CX, DX, BP, SI, DI, DS and ES.
-
- ? Predicate. False if no error has been
- recorded in the error flag, true if a notation
- exists. In the latter case, the two-byte
- value of the flag is placed on the PDL. This
- value is the address of the last location from
- which the error notation routine was called.
- No indication is given as to how many errors
- have occurred if this predicate is true. The
- error flag is reset after being consulted.
-
- Before proceeding to show examples of this last group of
- operators and predicates, a few facts will be mentioned with regard
- to the CP/M operating system.
-
- In CP/M, a program residing on a disk is called into
- execution by means of a "command line", consisting of the program
- name followed by a space and any parameters that the program is to
- receive. This parameter string or "command line tail" is passed on
- to the program in the buffer starting at address 080H (hexadecimal);
- address 080H contains the character count of the string and the
- string is stored forward from address 081H. If the first two
- parameters of the command line tail are files, they are parsed and
- placed forward from locations 05CH and 06CH. A file name consists of
- a disk identifier, a name of up to 8 characters and an extension of
- up to 3 characters; omission of the disk designator causes a default
- of @ (which indicates the currently logged disk unit) before
- conversion to the internal disk-numbering scheme, the other two parts
- are blank filled on the right. When no filenames are identified, the
- file name buffer at 5CH is certain to contain eleven blanks starting
- at 05DH.
-
- When REC is called into execution and finds a file name at
- 05CH, it will attempt to open it, and read, compile and execute
- a program from it. Any parameters following this file name are
- treated as a command line tail to be received by the REC program at
- the beginning of its execution. For example, the command line
-
- rec80 sample file.one b:file.two
-
- causes the program from file SAMPLE.REC to be compiled and executed;
- this compiled program will have available to it the file name FILE.ONE
- expanded and stored in the buffer at 5CH, the file name B:FILE.TWO
- expanded and stored in the buffer at 6CH and the command line tail
- "FILE.ONE B:FILE.TWO" starting at 81H with the character count (19) in
- location 80H. The program from file SAMPLE may access this
- information through the operators given above, as illustrated in the
- following examples.
-
- [make a buffer in which to save the second file name
- and save it; type and return the buffer's address]
- (33 c pG '05D'H 12G & S ! T H;) M
-
- In this example, 33c creates a 33-byte buffer and its address; the pG
- which follows makes a copy of the address to be used later by the
- operator S; '05D'H12G copies the 12-byte expanded file name to the
- PDL, & exchanges data and address for S and S stores the 12 data bytes
- starting at the beginning of the 33-byte buffer. !TH converts the
- address to ASCII, types it and restores is to binary. The reason
- behind making a longer buffer is that CP/M requires a "file control
- block" (FCB) for its operation on disk files; prior to opening a file
- the last 21 bytes of the FCB should be 0. One way of initializing
- the rest of an FCB is illustrated by the next subroutine:
-
- [clear the upper 21 bytes of an FCB, given its
- address; leave the original address]
- (pG 12 + 7m (n d m '000000'H v:;)L;) C
-
- This subroutine uses pG to ensure a copy of the original
- address is left on the PDL upon completion. 12+ adds 12 to the
- address, which is the location forward from which we want to store
- zeros. 7m sets up a counter in the PDL, and a loop starts. The
- sequence n d m fetches the counter, decrements it and returns it to
- the PDL complement (if not zero), '000000'H makes a three-byte binary
- zero and v stores it forward from the current address, which it
- updates (adding three to it in this case) after storing. Notice that
- d in the inner loop will be true 7 times so that v will store the 21
- required zeros. The final L erases the address left over from the
- last execution of v.
-
- As an example of how the operators g and u may be used,
- consider the following subroutines.
-
- [Returns the address of the first nonblank character between
- two addresses, searching from highest to lowest]
- (& m (g (" "=) nL; (d) n; pG n & =; m:) ;) <
-
- [Similar to the previous routine, searching from lowest to
- highest]
- (m (u (" "=) dnL; pG n & =; m:) ;) >
-
- In both subroutines the top PDL argument is assumed to be the higher
- address; the argument next to the top should be the lower address.
- In the first subroutine the address left by g is explicitly
- decremented, whereas in the second the operator d is used only when a
- nonblank character is found. Operator & is used before predicate = in
- both subroutines to retain the limiting address of the search (the
- lowest address in the first case and the highest in the second);
- recall that predicate = always erases at least the top argument.
-
- Finally we exhibit an example in which l, y, s, P and r are
- used:
-
- [Execution of s and P, with diagnostics]
- {(N n s;) s
- (2- N n P;) P
- (&mm p&L n lyGr & @@; n "Datum too big" TL)} Q
-
- Subroutine Q must receive three arguments: the two required by s or
- P and the letter s or the letter P as the top argument. The first
- action taken is to exchange the letter and the buffer address and send
- both to the PDL complement [&mm]. The length of the datum to be
- stored is next placed on the PDL and the name of the subroutine to be
- called is retrieved [p&Ln]. The combination lyG puts on the normal
- end of the PDL a copy of the last argument sent to the PDL complement,
- which in this case is the buffer address; r replaces this address with
- its contents, i.e., leaves on the PDL the length of the buffer
- (assuming it was created by operator c). & exchanges this value with
- the given letter and @@ calls the subroutine whose name is that
- letter. If the letter is s, the length of the datum is tested
- against the buffer size, and if the former is less than or equal to
- the latter, the buffer address is retrieved and the datum is stored
- [Nns]; if the letter is P, 2 is subtracted from the buffer size (since
- P requires two bytes from the buffer to store the datum's length) and
- a comparison is performed before retrieving the address and executing
- operator P. If in either s or P the comparison turns out to be false,
- predicate @@ becomes false, the address is retrieved and an error
- message is sent to the console; both datum and buffer address remain
- on the PDL, but subroutine Q terminates logically false.
-
- One more item worth noting in the above subroutine is the use
- of lyG, which although it produces results identical to the
- combination npGm, it generates less movement of bytes on the PDL,
- especially when the argument being copied is several bytes long.
-
- The last group of operators which take their arguments from
- the PDL is composed of input and output operators.
-
- Operator Function performed
-
- t Operator. Given an address "org" (as top
- argument) and a length "l" (as lower
- argument), t displays on the console the
- string of l characters stored in memory
- starting at address org. Both arguments are
- lifted from the PDL. Notice that T is
- equivalent to the operator pair pt; t is more
- often used in combination with q, an operator
- described in the next chapter.
-
- W Operator whose arguments are identical to
- those required by t, but which sends the
- character string described by the argument to
- the device logged in the operating system as
- the list device (the LST: device of CP/M;
- usually a printer). W also removes both of its
- arguments from the PDL after using them.
-
- i Operator. Given an argument on the PDL whose
- least significant byte represents the number
- of one of the computer's communication ports,
- i reads in a byte from that port, which it
- leaves on the PDL as top argument. The
- original argument stays on the PDL so that it
- may be reused after disposing of the byte read
- by i.
-
- o Operator requiring two arguments, the lower
- one such that its least significant byte is
- the number of a port and the top a byte to
- be written to that port. o outputs the given
- byte to the indicated port and lifts the byte
- from the PDL. The port number stays on the
- PDL, facilitating multiple outputs to the same
- port.
-
- It should be clear that operators i and o afford the user
- detailed control of the peripheral resources of the computer, but for
- the same reason its use results in REC programs which are extremely
- dependent on the specific configuration of the computer for which
- they are written; consequently these two operators have not been
- used very frequently.