home *** CD-ROM | disk | FTP | other *** search
-
-
- Chapter 5. Variables, the Compiling Operator
- and the CP/M Interface
-
-
- Variables in REC consist of an array of two-byte words which
- the programmer may use to store data or addresses of data. A single
- operator gives access to this array, as well as to the array of
- subroutine names; we now describe this operator.
-
- Operator Function performed
-
- $ Takes a one- or two-byte argument from the
- PDL, whose value lies between 0 and 127, and
- replaces is with the address belonging to
- that number in the variable and subroutine
- name table. Values between 0 and 32 and the
- value 127 are used as variables, as they
- correspond to control characters in the ASCII
- alphabet and thus are not used as subroutine
- names; values from 33 to 126 correspond to
- the ASCII printing characters, which may be
- used as subroutine names (except @ and }).
-
- Operator $ is almost always used together with operators S
- and r, which allow the program to store and retrieve data (c.f.
- Chapter 3), respectively. For instance, 'FA'25$S leaves the pair of
- ASCII characters FA in the table cell corresponding to variable 25;
- 'm'$r leaves on the PDL, in place of the letter m, the address at
- which subroutine m starts (so that 'm'$r@@ has the same effect as
- 'm'@@ or @m).
-
- If one wants to put aside a datum whose length is other than
- two bytes, the PDL may be used to hold it and a variable may contain
- its PDL address. For example, an address may be used to keep the
- address of a File Control Block (FCB) created as shown in Chapter 3.
- We reproduce here the corresponding subroutines with slight
- modifications, together with a new subroutine which calls the
- previous two subroutines and stores in variables 30 and 31 the
- addresses of two blocks corresponding to the command line tail
- filenames appearing at locations 005CH and 006CH.
-
- [creates an FCB on the PDL for the file whose name starts
- at the address given on the PDL]
- (m 33 c pG n 12G &S;) M
- [clears the upper 21 bytes of an FCB]
- (pG 12+ 21 w 0% (f:;) w;) C
- [makes FCBs for the filenames at 5C and 6C]
- ('05C'H@M@C 30$S '06C'H@M@C 31$S;) F
-
- It can be seen that subroutine M has been generalized so that
- it receives in the PDL the address from which it is to obtain the
- name of the file whose FCB it makes, instead of using a fixed
- address; also, it no longer types the address of the created block.
- Subroutine C uses the workspace operators w and f to fill with zeros
- the upper 21 bytes of the FCB. Once subroutine F has been called,
- and as long as the blocks are not lifted from the PDL, 30$r and 31$r
- may be used to retrieve the addresses of the FCBs and thus have
- access to them, no matter how many more arguments have been piled up
- on the PDL. These subroutines may be improved so that blocks are not
- made for files whose names are entirely blank; this is easily
- accomplished by the tests '05D'H1G" "= and '06D'H1G" "=, since if the
- first character of the filename is a blank, it is certain that the
- rest of the name is also blank.
-
- The PDL complement may also be used to store data. In this
- case, the combination ml20$s, for example, stores in variable 20 the
- value of pz where the datum sent to the PDL complement by m starts.
- As long as n is not used to remove this datum, we can use, in this
- example, the combination 20$ryG to put on the normal end of the PDL a
- copy of the stored datum without disturbing the PDL complement's
- contents.
-
- We now extend the parsing program given towards the end of
- Chapter 4 so that it evaluates the parsed expression, if the parse
- succeeds. Evaluation will require that in all exponentiations the
- exponent be an integer. The program also establishes precedence and
- associativity rules for operators, as follows:
-
- (a) Expressions enclosed in parentheses are evaluated
- first.
-
- (b) ** and ^ are evaluated before * and /; * and / are
- evaluated before + and -.
-
- (c) ** and ^ associate from right to left; e.g., 2^3^2 is
- evaluated as 2^(3^2), whose is different from that of
- (2^3)^2
-
- (d) * and / associate from left to right; e.g., 4*5/6 is
- evaluated as (4*5)/6, whose value is different to
- that of 4*(5/6)
-
- (e) + and - associate from left to right.
-
- The complete program is the following:
-
- [Algebraic notation arithmetic expression evaluator]
- {("0""9"Mz;) d [digit]
- (@d:;) D [0 o more digits]
- (qL('E'Ez;'D'Ez;)(@a;;) @d@D L;Yj;) E [power of 10 factor]
- (Z< (@d@D'.'Ez; J'.'Ez@d; J@d; Jj>)
- >@D@E;) q [number]
- ('+'Ez; '-'Ez;) a [additive operator]
- ('*'Ez; '/'Ez;) m [mult. operator]
- ('**'Ez; '^'Ez;) i [exp. operator]
- (@i; @m; @a;) o [operator]
- (@q; '('Ez @e ')'Ez;) p [operand]
- (Z<(@p;J@a@p;J>)>
- (qL@o@pL:Y;);) e [expression]
-
- ( [final adjustment]
- J('+'ED; '-'Ej'0'I;;) [initial +, -]
- J('(+'FAD:;) J('(-'FAj'0'I:;) [other unary +, -]
- J('**'FD'^'I:;) [all ** to ^]
- J 0,127$S 0m ;) A [initialize]
-
- ( [evaluate the formula]
- ('(' ED @(: [nest down]
- ')' ED @): [nest up]
- Z<@q JQDO>: > [number to the PDL]
- @i 4 @c: [operator ^]
- @m 2 @c: [operator * o /]
- @a 1 @c: ;) [operator + o -]
- (n0=; Ln @@:) ;) f [evaluate pending]
-
- (127$r5+,127$S;) ( [nest down]
- (127$r5-,127$S;) ) [nest up]
-
- ( [compute or push]
- 127$r+ [add nest weight]
- (pG lyG N [compare weights]
- I [new smaller, store]
- nL [lift previous weight]
- n @@ [evaluate previous]
- QD: [get weight, repeat]
- ;)
- 5/ 5* & (4= 3;;) + [reduce ^ weight]
- BQD mm;) c
-
- (+;) + (-;) - (*;) * [addn, subt, prod]
-
- (/ [division]
- p&L4N [integer?]
- &L; [yes, lift residue]
- ;) / [no, exit]
-
- ( [a^b]
- p4(N) [integer expt.?]
- "Error in exponent"T_; [no, abort]
- L [yes, go on]
- ((p&L 2= [exponent sign]
- pG32767;LpG00&;) [2 or more bytes?]
- N; [positivo: exit]
- ~m [no, check base]
- (d^) "0**x, x<0" T_; [base 0, abort]
- 1&@/n;) [not 0, reciprocal]
- 1m [initial factor]
- (d^) [expt. = 0?]
- (d [yes; base = 0?]
- ^ nL; [no, result=base]
- "0**0"T_;); [0**0, abort]
- (dd^^ [expt. = 1?]
- 2/ & [no, divide]
- (d [residue 1?]
- L &pGn * m; [yes, multiply]
- &;) [no]
- pG * &: [square]
- n*;) [last product]
- ;) ^ [end of subroutine ^]
-
- (R 13%=""; T@J|;) J [get line]
-
- (2573TL '> 'TL @J ""=;
- JZD I @e (A) @A @f '='TL#TL: ": no" TL:)} [main]
-
- This program is intended to be compiled and run with REC80F
- or REC86F, the REC versions handling numeric operands up to 8 bytes
- long (floating point). It could be run with REC80 or REC86, whose
- arithmetic operators recognize only (integer) operands up to 2 bytes
- in length. In any case, the division subroutine / may give
- apparently strange results when its operands are two-byte integers,
- since, as it was explained in Chapter 3, division of operands of this
- type considers them to be unsigned quantities, so that the expression
- 4/(-1), to give an example, causes the program to return 0 as the
- result, because the operation carried out in effect is 4/65535.
-
- The operation of the program shown above is the following:
- Once subroutine e has succeeded in parsing an arithmetic expression,
- the main program calls subroutine A to eliminate all unary +'s,
- convert all unary -'s to binary operators by inserting zeros and
- change all **'s to ^'s. When this is done, subroutine f is called to
- evaluate the expression, which is done by reading it left to right.
-
- The precedence rules we stated before are implemented by
- assigning weights to the operands, so that + and - have weight 1, *
- and / are assigned a weight of 2, and ^ gets a weight of 4 (the
- larger the weight, the greater the precedence of evaluation);
- variable 127 is used to keep track of how deeply parentheses have been
- nested, in the form of a multiple of 5, which is added to the weight
- of operators found at that parenthesis level; this guarantees that
- all of the operators contained within a given parenthesis level have
- higher precedence than operators at an outer level. Associativity is
- dictated by the evaluation algorithm contained in subroutine c, which
- stacks operators on the PDL complement or executes them (by using
- predicate @@) depending on the relation between the weight of the
- operator submitted to it by subroutine b and that of the top operator
- on the PDL complement (which contains 0 initially); the associativity
- rule for ^ demands that its weight be reduced when a comparison
- requires this operator to become stacked.
-
- Before going on to describe the compiling operator C, it is
- convenient to mention some features of the compiling area. This area
- has associated with it three pointers: c0, c1 and c2, which point to
- the physical lower bound, the next available address and the physical
- upper bound of the compiling area, respectively. Once REC has
- compiled a program (as a result of its own execution, not that of
- operator C), the value of c1 is preserved throughout the execution
- of the compiled program, which occupies memory bracketed by c0 and c1;
- c1 is stored during execution of C and is restored once C has
- performed its function. We proceed now to the description.
-
- Operator Function performed
-
- C Compiles a REC program, consulting the PDL
- for data on the program's source and the
- address at which the compiled program is to
- reside; besides leaving the compiled program
- at the desired location, C leaves two
- addresses on the PDL, the starting address of
- the object (as top argument) and the address
- following the object's last one (usually the
- next available address in the compiling area)
- as the PDL's lower argument. The argument
- indicating tha address at which the object is
- to start must be the top one on the PDL and
- may have either of two forms: the null string
- or an address (in two bytes); the null
- string indicates that the program compiled
- by C must start following the program
- initially compiled by REC and an address
- indicates the actual address where the
- compiled program is to begin. In general,
- the address provided in the latter alternative
- should be one of those returned by a previous
- use of C. The lower argument, which
- indicates the source of the REC program, may
- have one of three forms: the null string,
- indicating the source is the console
- keyboard, a one-byte argument indicating the
- source is a disk file residing in the disk
- unit designated by that byte, or a two-byte
- argument representing a length and indicating
- that the source program is in memory. The
- last two options imply that still one more
- argument must be on the PDL with one exception
- noted below; in the first case it should be a
- string of up to 11 characters giving the name
- and extension of the disk file (the extension
- is assumed to be REC if not included
- explicitly); in the second case the additional
- argument is the starting address of the source
- program and must be a two-byte argument (four
- bytes are also allowed in the 8086 version).
- The exception occurs when a two-byte argument
- representing a length is zero, in which case
- no more arguments are sought and, instead of
- compiling, C leaves on the PDL an address c1'
- and a length c2-c1', where c1' is the address
- determined by the destination argument given
- to C. In the 8086 version c1' is four bytes
- long; the upper word contains the value of
- the code segment base.
-
- If C is given an address lower than c1 for the object
- program's start, the compiled program will be written over the
- original program, the most likely result being a processor "hang",
- i.e., that the computer ceases to respond. Because of this, some
- care should be exercised in choosing the argument indicating the
- address and should normally be the null string (implyimg the use of
- the fixed value of c1) or one of the addresses left by C on the PDL.
-
- When REC or the operator C compile a program whose last
- address exceeds c2, the error message "Cp ovfl" is issued to the
- console, program execution is abandoned and control returns
- immediately to CP/M.
-
- Some examples of program fragments invoking C:
-
- """"C Reads a REC program from the keyboard; the
- compiled program starts at c1, the value of
- c1 is left as top argument and the address
- of the next available byte in the compiling
- area is left as lower PDL argument.
-
- "ABC""B"""C Compiles the program contained in file
- B:ABC.REC; the compiled program starts at c1
- and the PDL is left with arguments as
- described in the previous example.
-
- "FILENAMEEXT"
- "@"""C Searches the currently logged disk for the
- file FILENAME.EXT, to compile the REC program
- it contains. The result on the PDL is the
- same as above.
-
- q""C In this case, C is being directed to find the
- source program between pointers p1 and p2 in
- the wokspace.
-
- p""C Analogous to the last example, but the source
- is now on the PDL (and must be the argument
- to which p is applied in this example).
-
- 0""C Replaces its arguments on the PDL with the
- values of c1 (as the lower argument) and
- c2-c1 (as the top).
-
- Operator C causes an error message "Rd ovfl" to be issued and
- execution to be terminated if the program being compiled contains
- syntax errors, which may be due to insufficient right parentheses or
- braces, lack of a main program in a subroutine group enclosed in
- braces or unbalanced quotation marks. All of these circumstances
- cause an attempt to continue the compilation beyond the end of the
- file or memory area containing the source program, this is why they
- are grouped under the generic message "Rd ovfl".
-
- C can be used in combination with operator $ to compile
- programs contained in separate files, which can then be called as
- subroutines. For instance,
-
- ('SUB1'"A"""C '1'$S m 'SUB2'"A" nC '2'$S 0$S;)
-
- compiles the programs contained in files A:SUB1.REC and A:SUB2.REC.
- The starting address (c1) of the first one is saved under subroutine
- name "1" ['1'$S] and may be called by @1; the second program's
- starting address (which is the first following the first subroutine;
- note the use of m and n) is stored in the subroutine name table under
- the name "2", its execution is accomplished by the predicate @2.
- Finally, the address of the next available byte in the compilation
- area is saved in variable 0 [0$S], foreseeing the possibility of
- compiling still another program without destroying subroutines 1 and
- 2.
-
- A use of C which allows executing programs whose length
- exceed the size of the compilation area is that of overlay
- construction. Consider the following example:
-
- {[compiles and executes the program whose source and
- destination are on the PDL]
- (C &0$S @@;) X
-
- [main program: alternates executions of B:PROG1.REC
- and B:PROG2.REC, until either of them becomes false]
- ("PROG1" 'B' ""@X "PROG2" 'B' ""@X:;)}
-
- Subroutine X compiles the program whose source is indicated by the
- argument(s) it receives on the PDL, places the object in memory
- starting at c1 (when the top argument is the null string), stores the
- final address in variable 0 [&0$S] and executes the compiled program
- [@@]; the main program calls @X alternating executions of PROG1 and
- PROG2; the compilation of each of these programs overwrites the
- previous one's object program; PROG1 and PROG2 can communicate data
- through the PDL or the workspace. Notice that PROG1 and PROG2 may in
- turn contain calls to X of the form "PROG3"'A'0$rpGm@Xn0$S, where the
- initial address for the object is now given by variable 0 and is the
- next available address in the compilation area, relative to the
- program containing the predicate @X, and the PDL complement is used to
- stack a copy of the current value of variable 0 (since it will be
- changed by subroutine X); this way overlay trees may be built.
-
- We end this chapter with a discussion of the operators which
- provide the user with an interface to CP/M, the operating system:
-
- Operator Function performed
-
- _ (Underscore.) Returns immediately to CP/M.
-
- K Calls the operating system to execute the
- function whose number is given by the top PDL
- argument (which should be two bytes long)
- with the lower argument copied to register DE
- (DX on the 8086). The lower argument remains
- on the PDL after K is executed, and the top
- argument is replaced by the resulting value
- of register A (AL on the 8086) extended to a
- two-byte value by adjoining a zero upper byte;
- this value usually indicates success or
- failure in the execution of the CP/M function
- requested.
-
- k Identical to K, but lifts both arguments and
- leaves no A value behind; it is mainly used
- to request functions for which it is not
- necessary to check the value of A returned
- by CP/M.
-
- When the 8086 processor is used, the lower argument of K or k
- may be four bytes long, representing an address and a memory segment
- base; in this case the DS register value is saved, the segment base
- portion of the argument is transferred to DS, the function is
- executed and the previous value of DS is restored. If the function
- requested is function number 26 (set DMA address), CP/M is called
- first to perform function 51 (set DMA segment base) with the segment
- base indicated by the lower argument (the data segment if this
- argument is two bytes long, the explicit base given if the lenght is
- four) and then the call to CP/M for function 26 is carried out.
-
- Not all CP/M functions require a value in DE (or DX); for
- those functions not needing it the PDL must still contain the
- corresponding two-byte argument in its place, 0 is recommended.
-
- The use of operators K and k requires a thorough knowledge of
- the operation of CP/M function calls (for example, CP/M must be
- requested to open a file before reading from it, or to close a file
- used for writing in order to update the disk's directory and hence be
- able to access the data later, etc.), however, the discussion of all
- possible variants is beyond the scope of this book, so we refer the
- reader to the bibliography given at the end. We limit ourselves here
- to giving a list of possible functions and illustrating the use of
- the more important ones.
-
- In the following table, "Num" is the value which the top
- argument must have, "DE" is the kind of datum the lower argument
- should be and "Value" is the value K returns as top argument. A dash
- in column "DE" indicates that the argument is not used (although both
- K and k require something in its place, usually a zero) and a dash in
- the "Value" column indicates that no specific value is returned in A
- (or AL) and hence the value left by K has no significance.
-
- As regards the abbreviations used in the table, "char"
- represents a character (to be written, if under "DE"; read if under
- "Value"), "FCB" represents the address of a file control block which
- can be created as shown in Chapter 3 or at the beginning of this
- chapter, "stat" indicates the datum contains a byte with the status
- referred to by the corresponding function, "buf" is the address of
- a buffer to be used for data transfer, "DMA" is the address of a
- 128-byte buffer to be used in operations to be subsequently performed
- on disk files, "id" is a disk identifier (0 for disk A, 1 for disk B,
- etc.) and "ind" means the returned value indicates the success or
- failure of the function. The number 80 or 86 next to the function
- number means that line is applicable to the version of CP/M for the
- 8080 or 8086, respectively.
-
-
- TABLE I. CP/M Functions
- =====================================================================
- Num Function DE Value
- =====================================================================
- 0 System reset - -
- 1 Read from console - char
- 2 Write to console char -
- 3 Read from reader - char
- 4 Write to punch char -
- 5 Write to printer char -
- 6 (80) Read direct from console 255 char or 0
- 6 (80) Write direct to console char -
- 6 (86) Read direct from console 255 char
- 6 (86) Read console status 254 stat
- 6 (86) Write direct to console char -
- 7 Read I/O byte - stat
- 8 Write I/O byte stat -
- 9 Write string to console buf -
- 10 Read string from console buf -
- 11 Read console status - stat
- 12 Read version number - ind
- 13 Reset disk system - -
- 14 Select disk id -
- 15 Open file FCB ind
- 16 Close file FCB ind
- 17 Search for first instance FCB ind
- 18 Search for next instance - ind
- 19 Delete file FCB ind
- 20 Read a sector sequentially FCB ind
- 21 Write a sector sequentially FCB ind
- 22 Make file FCB ind
- 23 Rename file FCB ind
- 24 Read logged disk vector - stat
- 25 Read logged in disk id - id
- 26 Set DMA address DMA -
- 28 Write protect disk - -
- 30 Set file attributes FCB ind
- 32 Get user code 255 ind
- 32 Set user code 0 to 15 -
- 33 Read random FCB ind
- 34 Write random FCB ind
- 35 Compute file size FCB -
- 36 Set random record FCB -
- 37 (86) Reset selected disks stat -
- 40 (86) Write random with zero fill FCB ind
- 50 (86) Direct BIOS call buf ind
- =====================================================================
-
- As an example of K and k usage, assume FCBs have been
- created by means of subroutines M, C and F shown earlier in this
- chapter. Then, the following subroutines can be used to open, close,
- make, read and write the files described by the FCBs.
-
- [set DMA buffer at absolute address 128]
- ('080'H 26k;) h
-
- [delete file if present]
- (@h $r 19k;) g
-
- [open file or create it]
- (@h $r 15K (255= 22K 255= "Directory full"T_;;) LL;) e
-
- [open file or report absence]
- (@h $r 15K (255= ^11G T ": Not found"T_;;) LL;) f
-
- [open for reading file denoted by variable 30,
- open for writing file denoted by variable 31]
- (30@f 31@g 31@e;) G
-
- [write 128 workspace bytes to the output file [var. 31],
- false if less then 128 bytes in workspace]
- (Jj 26%EZD 0; 128a qL 26k 31$r
- 21K(0= L;
- 1= "Directory full"T_;
- "Disk full"T_)
- D'.'T;) p
-
- [write workspace from p0 to p1 to the output file]
- (jJ < (@p '.'=: 0=: L;) Zz>;) P
-
- [append a sector from the input file [var. 30],
- false when there is no more data to read]
- (128(e) "WS full"T_; qL 26k 30$r 20K 0=L; DLL) y
-
- [empty workspace to the output file, copying what is
- left of the input file, and close the output file]
- (@p '.'=: L@y: (@p '.': 0=; e 26%(f:;) @p L; L;)
- 31 $r 16k;) H
-
- These subroutines could be a part of some program that reads
- from the input file to the workspace with @y and writes the processed
- data to the output file with @P; a call to subroutine H at the end
- would ensure that the output file is properly closed; the one byte
- value 26 [26%] used by H to fill the last sector of the output file
- is the ASCII character control-Z used by CP/M to signal the end of
- data in an ASCII text file.
-
-
-
- Chapter 6. Operation of REC and User-supplied
- Extensions
-
- The execution of REC for running programs interactively is
- initiated by a command line which simply contains the name of the
- desired REC compiler (which may be REC80, REC80, REC80F or REC86F,
- depending on the processor used and whether floating point arithmetic
- is desired). If a command line containing only, say, REC80F is given
- to CP/M, execution begins with the following message displayed on the
- console (REC80 produces a similar display):
-
- REC(8080)/ICUAP
- Universidad Autonoma de Puebla
- [date]
-
- CPL ccccc
- PDL ppppp
- WS wwww
- Stk ssss
-
- REC80F>
-
- ICUAP means "Institute of Sciences of the Autonomous
- University of Puebla", [date] is the date of the REC version being
- executed, ccccc, ppppp, wwww and ssss are decimal numbers indicating
- the sizes in bytes of the areas available for compilation, pushdown
- list, workspace and machine stack, respectively. (When REC86 or
- REC86F are executed, additional data in hexadecimal is displayed
- giving the segment base and length for each of the four memory
- segments used by these compilers.)
-
- "REC80F>" in the above example is the prompt indicating that
- REC is ready to read and execute a program. The program may be
- entered in one or more lines terminated by carriage returns (ASCII
- CR); REC starts execution of the compiled program as soon as it
- recognizes the final right parenthesis or brace. When entering
- programs in this manner, care has to be taken to ensure that all
- parentheses, braces, brackets and quotation marks (single and double
- quotes) are correctly balanced; this is why the interactive execution
- of REC is only recommended for testing simple programs or program
- fragments.
-
- As stated in Chapter 3, the execution of REC may also include
- additional data on the command line, in which case REC takes the
- first paramater on the command line tail to be the name of a file
- containing the program whose compilation and execution is desired; if
- the given name does not contain an explicit extension, the extension
- REC is assumed, so that the command lines
-
- REC80 EXAMPLE
-
- REC80 EXAMPLE.REC
-
- produce identical results. When REC is executed in this manner, no
- display occurs on the console other than what the compiled REC
- program itself produces; when this program's execution ends, REC
- returns control of the computer to CP/M. If the file named on the
- command line does not exist, REC returns to CP/M with no further
- indication of the error.
-
- One letter of the ASCII alphabet, X, has been set aside to
- provide access to user-defined operators (other than those defined as
- subroutines in REC). The compilation of X requires that it be followed
- by a character that becomes a part of the calling sequence generated by
- the compiler (in the style of @x); this character is analyzed by the
- run-time subroutine provided by the user to identify the particular
- operator whose execution is desired. Specifically, Xa is compiled as an
- operator, with the following calling sequence:
-
- CALL LIBO
- DB 'a'
-
- The user-written extension must contain the entry point LIBO
- (which in the case of REC80 and REC80F must appear in an ENTRY
- directive if an assembler like Microsoft's M80 is used), and
- this program must be relinked with the rest of the REC compiler
- (reassembled in case one uses ASM86 to assemble REC86 or REC86F).
- Further on an example is given of the basic code required for
- implementing operator X.
-
- The REC80 source program is divided into five modules:
-
- - REC80, which contains the compiling routines,
- - PDL80, which contains the PDL predicates and operators,
- - MKV80, which contains the workspace operators and
- predicates,
- - LIB80, which contains the definition for predicate x, and
- - FXT80, which contains tables, the CP/M interface and the
- initializing routine; all other modules must precede
- this one in memory.
-
- Once M80 has assembled the above four modules, the executable
- module REC80.COM is produced by the command line
-
- L80 MKV80,PDL80,REC80,LIB80,FXT80/E,REC80/N
-
- REC80F consists of seven modules, to wit,
-
- - FLT80F, which contains binary-ASCII and ASCII-binary
- conversion routines,
- - ATH80F, which contains the arithmetic operators, and
-
- REC80F, PDL80F, MKV80F, LIB80F and FXT80F, which contain functions similar
- to the analogously named REC80 modules.
-
- Analogously to REC80, the assembled modules may be linked
- with L80 to create a REC80F executable module with the following
- command line, which generates the file REC80F.COM:
-
- L80 MKV80F,PDL80F,ATH80F,FLT80F,REC80F,LIB80F,FXT80F/E,REC80F/N
-
- Notice that in this case it is also required to place module
- FXT80F last.
-
- For the 8086 versions, REC86 and REC86F, we have used
- CP/M-86's assembler ASM86. Even though the source programs for these
- compilers are kept in 5 and 7 separate modules, respectively, ASM86
- assembles all modules together directed by an additional small module
- containing only INCLUDE directives. Thus, to assemble REC86, ASM86
- is requested to assemble a file REC86.A86, containing the following:
-
- CSEG
- INCLUDE PDL86.A86
- INCLUDE MKV86.A86
- INCLUDE REC86A.A86
- INCLUDE LIB86.A86
- INCLUDE FXT86.A86
- END
-
- The source module containing the compilation routines of REC
- is now called REC86A; this is done so that ASM86 will produce, from
- the assembly of the above small program, a file named REC86.H86, from
- which the executable module REC86.CMD can be generated by GENCMD, a
- utility program provided by CP/M-86. The computer system on which
- REC86 was developed has 256kbytes of memory, of which 192k are
- contiguous and start at address 00000H and the remaining 64k start at
- address F0000H. The command line we have used to generate REC86.CMD
- is the following:
-
- GENCMD REC86 CODE[M1000] DATA[M1000] EXTRA[A0F000,M0FFF] STACK[M0C00]
-
- which allocates 64k for the code segment (which includes the compiler
- itself), 64k for the data segment (including REC's PDL and the
- compilation, variable and subroutine tables), 64k for the extra
- segment (containing the workspace) and 48k for the 8086's machine
- stack. The remaining 16k are used by CP/M-86.
-
- To end our description of the standard REC compilers, we note
- that the assembly of REC86F is similar to that of REC86, but in this
- case the small module whose assembly is requested to AASM86 is called
- REC86F.A86 and contains the following lines:
-
- CSEG
- INCLUDE PDL86F.A86
- INCLUDE MKV86F.A86
- INCLUDE ATH86F.A86
- INCLUDE FLT86F.A86
- INCLUDE REC86FA.A86
- INCLUDE LIB86F.A86
- INCLUDE FXT86F.A86
- END
-
- The generation of the executable module REC86F.CMD is
- accomplished by executing GENCMD with a command line entirely
- analogous to the one given for REC86.
-
- Suppose now that a user wants to add to REC80 the operators
- X0, X1, X2, X3 and X4, and that any other predicate of the form Xa
- should effect an immediate return. The user would then provide a new
- module, say UOP80.MAC, which would contain the following program (in
- which the explicit processes represented by the five new operators
- are omitted):
-
- ENTRY LIBO ;Declare LIBO to be an entry point
- ;
- LIBO: POP H ;Pick up the return addr (calling seq. pointer)
- MOV A,M ;Copy the character from the calling sequence
- INX H ;Get the actual return address
- PUSH H ;push it back on the stack
- CPI '5' ;Is the char. less than or equal to ASCII 5?
- RNC ;exit if not
- SUI '0' ;Is the char. greater than or equal to 0?
- RC ;exit if not
- ;
- ; Notice that register A now contains a value between 0 and 4
- ;
- ADD A ;Multiply A by 2,
- MOV C,A ;pass on to C,
- MVI B,0 ;extend to 2 bytes with a zero in B.
- LXI H,TAB ;The origin in the table of addresses
- ; ;of subroutines X0 to X4
- DAD B ;added to BC gives the address in the table
- ; ;of the desired subroutine's entry address
- MOV E,M ;which we copy to DE
- INX H
- MOV D,M
- XCHG ;pass on to HL
- PCHL ;and we jump to it.
- ;
- TAB: DW ZERO ;ZERO is the address of the subroutine for X0
- DW ONE ;ONE is X1's entry point
- DW TWO ; and so forth
- DW THREE
- DW FOUR
- ;
- ZERO: ... ;Here we insert the instructions which carry
- ; ;out the function associated with X0,
- ;
- ONE: ... ;In a similar manner for X1,
- ;
- TWO: ... ;X2,
- ;
- THREE: ... ;X3
- ;
- FOUR: ... ;and X4.
- ;
- END
-
- This module is assembled with M80 and linked to make an
- executable module as follows:
-
- L80 UOP80,MKV80,PDL80,REC80,LIB80,FXT80/E,UREC80/N
-
- where the new executable module's name is UREC80.COM.
-
- Finally, we mention the predicate xa, which provides a way
- to call predicates added to a REC program using operator C after
- its execution has begun. xa operates in a manner similar to @a
- in the sense that it calls a predicate whose address is in a table
- indexed by the ASCII character a; the difference is that @ always
- refers to a fixed table, whereas the table referenced by x may be
- changed.
-
- x@ is a predicate which takes, like @@, an argument from
- the PDL; if it is a single byte, it is assumed to be an ASCII
- character to be used as an index to the current table (for instance,
- '$'x@ has the same effect as x$). However, if the PDL argument is
- a two-byte value, it must be the address of a new table (whose
- indices are the ASCII characters exclamation point (!) through
- tilde (~)), from which predicate x will take execution addresses
- in subsequent uses, and until a new table is given by a further
- execution of x@ with a two-byte argument.
-
- At the start of REC's execution, predicate x refers to the
- same table as @, so that xa and @a produce the same result. Once
- the table referenced by x is changed, it is possible to reset it
- to the initial state by the use of '!'$x@, since '!'$ places on
- the PDL the address of the portion of the table of subroutines
- (called by @) starting at character "!". Note that the mechanism
- whereby braces ({ and }, see Chapter 1) deactivate external definitions
- to activate internal ones only affects the table used by @ and not
- that referenced by x, if the latter table is different from the former.
-
- This predicate has been used in the CONVERT compiler to
- effect automatic inclusion of programs from a library when execution
- of a Convert program is begun.