home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MISC / REC.ZIP / RECD.DOC < prev   
Encoding:
Text File  |  1986-12-01  |  33.5 KB  |  802 lines

  1.  
  2.  
  3.         Chapter 5.  Variables, the Compiling Operator
  4.                 and the CP/M Interface
  5.  
  6.  
  7.     Variables in REC consist of an array of two-byte words which 
  8. the programmer may use to store data or addresses of data.  A single 
  9. operator gives access to this array, as well as to the array of 
  10. subroutine names; we now describe this operator.
  11.  
  12.      Operator            Function performed
  13.  
  14.     $        Takes a one- or two-byte argument from the 
  15.             PDL, whose value lies between 0 and 127, and 
  16.             replaces is with the address belonging to 
  17.             that number in the variable and subroutine 
  18.             name table.  Values between 0 and 32 and the 
  19.             value 127 are used as variables, as they 
  20.             correspond to control characters in the ASCII 
  21.             alphabet and thus are not used as subroutine 
  22.             names; values from 33 to 126 correspond to 
  23.             the  ASCII printing characters, which may be 
  24.             used as subroutine names (except @ and }).
  25.  
  26.     Operator $ is almost always used together with operators S 
  27. and r, which allow the program to store and retrieve data (c.f. 
  28. Chapter 3), respectively.  For instance, 'FA'25$S leaves the pair of 
  29. ASCII characters FA in the table cell corresponding to variable 25; 
  30. 'm'$r leaves on the PDL, in place of the letter m, the address at 
  31. which subroutine m starts (so that 'm'$r@@ has the same effect as 
  32. 'm'@@ or @m).
  33.  
  34.     If one wants to put aside a datum whose length is other than 
  35. two bytes, the PDL may be used to hold it and a variable may contain 
  36. its PDL address.  For example, an address may be used to keep the 
  37. address of a File Control Block (FCB) created as shown in Chapter 3.  
  38. We reproduce here the corresponding subroutines with slight 
  39. modifications, together with a new subroutine which calls the 
  40. previous two subroutines and stores in variables 30 and 31 the 
  41. addresses of two blocks corresponding to the command line tail 
  42. filenames appearing at locations 005CH and 006CH.
  43.  
  44.     [creates an FCB on the PDL for the file whose name starts
  45.      at the address given on the PDL]
  46.     (m 33 c pG n 12G &S;) M
  47.     [clears the upper 21 bytes of an FCB]
  48.     (pG 12+ 21 w 0% (f:;) w;) C
  49.     [makes FCBs for the filenames at 5C and 6C]
  50.     ('05C'H@M@C 30$S '06C'H@M@C 31$S;) F
  51.  
  52.     It can be seen that subroutine M has been generalized so that 
  53. it receives in the PDL the address from which it is to obtain the 
  54. name of the file whose FCB it makes, instead of using a fixed 
  55. address; also, it no longer types the address of the created block.
  56. Subroutine C uses the workspace operators w and f to fill with zeros 
  57. the upper 21 bytes of the FCB.  Once subroutine F has been called, 
  58. and as long as the blocks are not lifted from the PDL, 30$r and 31$r 
  59. may be used to retrieve the addresses of the FCBs and thus have 
  60. access to them, no matter how many more arguments have been piled up 
  61. on the PDL.  These subroutines may be improved so that blocks are not 
  62. made for files whose names are entirely blank; this is easily 
  63. accomplished by the tests '05D'H1G" "= and '06D'H1G" "=, since if the 
  64. first character of the filename is a blank, it is certain that the 
  65. rest of the name is also blank.
  66.  
  67.     The PDL complement may also be used to store data.  In this 
  68. case, the combination ml20$s, for example, stores in variable 20 the 
  69. value of pz where the datum sent to the PDL complement by m starts.  
  70. As long as n is not used to remove this datum, we can use, in this 
  71. example, the combination 20$ryG to put on the normal end of the PDL a 
  72. copy of the stored datum without disturbing the PDL complement's 
  73. contents.
  74.  
  75.     We now extend the parsing program given towards the end of 
  76. Chapter 4 so that it evaluates the parsed expression, if the parse 
  77. succeeds.  Evaluation will require that in all exponentiations the 
  78. exponent be an integer.  The program also establishes precedence and 
  79. associativity rules for operators, as follows:
  80.  
  81.     (a)    Expressions enclosed in parentheses are evaluated 
  82.         first.
  83.  
  84.     (b)    ** and ^ are evaluated before * and /; * and / are 
  85.         evaluated before + and -.
  86.  
  87.     (c)    ** and ^ associate from right to left; e.g., 2^3^2 is 
  88.         evaluated as 2^(3^2), whose is different from that of 
  89.         (2^3)^2
  90.  
  91.     (d)    * and / associate from left to right; e.g., 4*5/6 is 
  92.         evaluated as (4*5)/6, whose value is different to 
  93.         that of 4*(5/6)
  94.  
  95.     (e)    + and - associate from left to right.
  96.  
  97.     The complete program is the following:
  98.  
  99.     [Algebraic notation arithmetic expression evaluator]
  100.     {("0""9"Mz;) d                [digit]
  101.      (@d:;) D                [0 o more digits]
  102.      (qL('E'Ez;'D'Ez;)(@a;;) @d@D L;Yj;) E    [power of 10 factor]
  103.      (Z< (@d@D'.'Ez; J'.'Ez@d; J@d; Jj>)
  104.          >@D@E;) q            [number]
  105.      ('+'Ez; '-'Ez;) a            [additive operator]
  106.      ('*'Ez; '/'Ez;) m            [mult. operator]
  107.      ('**'Ez; '^'Ez;) i            [exp. operator]
  108.      (@i; @m; @a;) o            [operator]
  109.      (@q; '('Ez @e ')'Ez;) p        [operand]
  110.      (Z<(@p;J@a@p;J>)>
  111.         (qL@o@pL:Y;);) e        [expression]
  112.  
  113.      (                    [final adjustment]
  114.       J('+'ED; '-'Ej'0'I;;)            [initial +, -]
  115.       J('(+'FAD:;) J('(-'FAj'0'I:;)        [other unary +, -]
  116.       J('**'FD'^'I:;)            [all ** to ^]
  117.       J 0,127$S 0m ;) A            [initialize]
  118.  
  119.      (                    [evaluate the formula]
  120.       ('(' ED @(:                [nest down]
  121.        ')' ED @):                [nest up]
  122.        Z<@q JQDO>: >            [number to the PDL]
  123.        @i 4 @c:                [operator ^]
  124.        @m 2 @c:                [operator * o /]
  125.        @a 1 @c: ;)                [operator + o -]
  126.       (n0=; Ln @@:) ;) f            [evaluate pending]
  127.  
  128.      (127$r5+,127$S;) (            [nest down]
  129.      (127$r5-,127$S;) )            [nest up]
  130.  
  131.      (                    [compute or push]
  132.       127$r+                [add nest weight]
  133.       (pG lyG N                [compare weights]
  134.        I                     [new smaller, store]
  135.        nL                    [lift previous weight]
  136.        n @@                    [evaluate previous]
  137.        QD:                    [get weight, repeat]
  138.        ;)
  139.       5/ 5* & (4= 3;;) +            [reduce ^ weight]
  140.       BQD mm;) c
  141.  
  142.      (+;) +   (-;) -   (*;) *        [addn, subt, prod]
  143.  
  144.      (/                    [division]
  145.       p&L4N                    [integer?]
  146.       &L;                    [yes, lift residue]
  147.       ;) /                    [no, exit]
  148.  
  149.      (                    [a^b]
  150.       p4(N)                    [integer expt.?]
  151.        "Error in exponent"T_;        [no, abort]
  152.       L                    [yes, go on]
  153.       ((p&L 2=                [exponent sign]
  154.         pG32767;LpG00&;)            [2 or more bytes?]
  155.         N;                    [positivo: exit]
  156.         ~m                    [no, check base]
  157.         (d^) "0**x, x<0" T_;        [base 0, abort]
  158.         1&@/n;)                [not 0, reciprocal]
  159.       1m                    [initial factor]
  160.       (d^)                    [expt. = 0?]
  161.        (d                    [yes; base = 0?]
  162.         ^ nL;                [no, result=base]
  163.         "0**0"T_;);                [0**0, abort]
  164.       (dd^^                    [expt. = 1?]
  165.        2/ &                    [no, divide]
  166.        (d                    [residue 1?]
  167.         L &pGn * m;                [yes, multiply]
  168.         &;)                    [no]
  169.        pG * &:                [square]
  170.        n*;)                    [last product]
  171.      ;) ^                    [end of subroutine ^]
  172.  
  173.      (R 13%=""; T@J|;) J            [get line]
  174.  
  175.      (2573TL '> 'TL @J ""=;
  176.       JZD I @e (A) @A @f '='TL#TL: ": no" TL:)}  [main]
  177.  
  178.     This program is intended to be compiled and run with REC80F 
  179. or REC86F, the REC versions handling numeric operands up to 8 bytes 
  180. long (floating point).  It could be run with REC80 or REC86, whose 
  181. arithmetic operators recognize only (integer) operands up to 2 bytes 
  182. in length.  In any case, the division subroutine / may give 
  183. apparently strange results when its operands are two-byte integers, 
  184. since, as it was explained in Chapter 3, division of operands of this 
  185. type considers them to be unsigned quantities, so that the expression 
  186. 4/(-1), to give an example, causes the program to return 0 as the 
  187. result, because the operation carried out in effect is 4/65535.
  188.  
  189.     The operation of the program shown above is the following:  
  190. Once subroutine e has succeeded in parsing an arithmetic expression, 
  191. the main program calls subroutine A to eliminate all unary +'s, 
  192. convert all unary -'s to binary operators by inserting zeros and 
  193. change all **'s to ^'s.  When this is done, subroutine f is called to 
  194. evaluate the expression, which is done by reading it left to right.  
  195.  
  196.     The precedence rules we stated before are implemented by 
  197. assigning weights to the operands, so that + and - have weight 1, * 
  198. and / are assigned a weight of 2, and ^ gets a weight of 4 (the 
  199. larger the weight, the greater the precedence of evaluation); 
  200. variable 127 is used to keep track of how deeply parentheses have been 
  201. nested, in the form of a multiple of 5, which is added to the weight 
  202. of operators found at that parenthesis level; this guarantees that 
  203. all of the operators contained within a given parenthesis level have 
  204. higher precedence than operators at an outer level.  Associativity is 
  205. dictated by the evaluation algorithm contained in subroutine c, which 
  206. stacks operators on the PDL complement or executes them (by using 
  207. predicate @@) depending on the relation between the weight of the 
  208. operator submitted to it by subroutine b and that of the top operator 
  209. on the PDL complement (which contains 0 initially); the associativity 
  210. rule for ^ demands that its weight be reduced when a comparison 
  211. requires this operator to become stacked.
  212.  
  213.     Before going on to describe the compiling operator C, it is 
  214. convenient to mention some features of the compiling area.  This area 
  215. has associated with it three pointers: c0, c1 and c2, which point to 
  216. the physical lower bound, the next available address and the physical 
  217. upper bound of the compiling area, respectively.  Once REC has 
  218. compiled a program (as a result of its own execution, not that of 
  219. operator C), the value of c1 is preserved throughout the execution
  220. of the compiled program, which occupies memory bracketed by c0 and c1;
  221. c1 is stored during execution of C and is restored once C has 
  222. performed its function.  We proceed now to the description.
  223.  
  224.      Operator            Function performed
  225.  
  226.     C        Compiles a REC program, consulting the PDL 
  227.             for data on the program's source and the 
  228.             address at which the compiled program is to 
  229.             reside; besides leaving the compiled program 
  230.             at the desired location, C leaves two 
  231.             addresses on the PDL, the starting address of 
  232.             the object (as top argument) and the address 
  233.             following the object's last one (usually the 
  234.             next available address in the compiling area) 
  235.             as the PDL's lower argument.  The argument 
  236.             indicating tha address at which the object is 
  237.             to start must be the top one on the PDL and 
  238.             may have either of two forms: the null string 
  239.             or an address (in two bytes); the null 
  240.             string indicates that the program compiled 
  241.             by C must start following the program 
  242.             initially compiled by REC and an address 
  243.             indicates the actual address where the 
  244.             compiled program is to begin.  In general, 
  245.             the address provided in the latter alternative 
  246.             should be one of those returned by a previous 
  247.             use of C.  The lower argument, which 
  248.             indicates the source of the REC program, may 
  249.             have one of three forms:  the null string, 
  250.             indicating the source is the console 
  251.             keyboard, a one-byte argument indicating the 
  252.             source is a disk file residing in the disk 
  253.             unit designated by that byte, or a two-byte 
  254.             argument representing a length and indicating 
  255.             that the source program is in memory.  The 
  256.             last two options imply that still one more 
  257.             argument must be on the PDL with one exception
  258.             noted below; in the first case it should be a 
  259.             string of up to 11 characters giving the name 
  260.             and extension of the disk file (the extension 
  261.             is assumed to be REC if not included 
  262.             explicitly); in the second case the additional 
  263.             argument is the starting address of the source 
  264.             program and must be a two-byte argument (four 
  265.             bytes are also allowed in the 8086 version).
  266.             The exception occurs when a two-byte argument
  267.             representing a length is zero, in which case
  268.             no more arguments are sought and, instead of
  269.             compiling, C leaves on the PDL an address c1'
  270.             and a length c2-c1', where c1' is the address
  271.             determined by the destination argument given
  272.             to C.  In the 8086 version c1' is four bytes
  273.             long; the upper word contains the value of
  274.             the code segment base.
  275.  
  276.     If C is given an address lower than c1 for the object 
  277. program's start, the compiled program will be written over the 
  278. original program, the most likely result being a processor "hang", 
  279. i.e., that the computer ceases to respond.  Because of this, some 
  280. care should be exercised in choosing the argument indicating the 
  281. address and should normally be the null string (implyimg the use of 
  282. the fixed value of c1) or one of the addresses left by C on the PDL. 
  283.  
  284.     When REC or the operator C compile a program whose last 
  285. address exceeds c2, the error message "Cp ovfl" is issued to the 
  286. console, program execution is abandoned and control returns 
  287. immediately to CP/M.
  288.  
  289.     Some examples of program fragments invoking C:
  290.  
  291.     """"C        Reads a REC program from the keyboard; the 
  292.             compiled program starts at c1, the value of 
  293.             c1 is left as top argument and the address 
  294.             of the next available byte in the compiling 
  295.             area is left as lower PDL argument. 
  296.  
  297.     "ABC""B"""C    Compiles the program contained in file 
  298.             B:ABC.REC; the compiled program starts at c1 
  299.             and the PDL is left with arguments as 
  300.             described in the previous example.
  301.  
  302.     "FILENAMEEXT"
  303.     "@"""C        Searches the currently logged disk for the 
  304.             file FILENAME.EXT, to compile the REC program 
  305.             it contains.  The result on the PDL is the 
  306.             same as above.
  307.  
  308.     q""C        In this case, C is being directed to find the 
  309.             source program between pointers p1 and p2 in 
  310.             the wokspace. 
  311.  
  312.     p""C        Analogous to the last example, but the source 
  313.             is now on the PDL (and must be the argument 
  314.             to which p is applied in this example).
  315.  
  316.     0""C        Replaces its arguments on the PDL with the
  317.             values of c1 (as the lower argument) and
  318.             c2-c1 (as the top).
  319.  
  320.     Operator C causes an error message "Rd ovfl" to be issued and 
  321. execution to be terminated if the program being compiled contains 
  322. syntax errors, which may be due to insufficient right parentheses or 
  323. braces, lack of a main program in a subroutine group enclosed in 
  324. braces or unbalanced quotation marks.  All of these circumstances 
  325. cause an attempt to continue the compilation beyond the end of the 
  326. file or memory area containing the source program, this is why they 
  327. are grouped under the generic message "Rd ovfl".
  328.  
  329.     C can be used in combination with operator $ to compile 
  330. programs contained in separate files, which can then be called as 
  331. subroutines.  For instance, 
  332.  
  333.     ('SUB1'"A"""C '1'$S m 'SUB2'"A" nC '2'$S 0$S;)
  334.  
  335. compiles the programs contained in files A:SUB1.REC and A:SUB2.REC.  
  336. The starting address (c1) of the first one is saved under subroutine 
  337. name "1" ['1'$S] and may be called by @1; the second program's 
  338. starting address (which is the first following the first subroutine; 
  339. note the use of m and n) is stored in the subroutine name table under 
  340. the name "2", its execution is accomplished by the predicate @2.  
  341. Finally, the address of the next available byte in the compilation 
  342. area is saved in variable 0 [0$S], foreseeing the possibility of 
  343. compiling still another program without destroying subroutines 1 and 
  344. 2.
  345.  
  346.     A use of C which allows executing programs whose length 
  347. exceed the size of the compilation area is that of overlay 
  348. construction.  Consider the following example:
  349.  
  350.     {[compiles and executes the program whose source and
  351.       destination are on the PDL]
  352.      (C &0$S @@;) X
  353.  
  354.      [main program: alternates executions of B:PROG1.REC 
  355.       and B:PROG2.REC, until either of them becomes false]
  356.      ("PROG1" 'B' ""@X "PROG2" 'B' ""@X:;)}
  357.  
  358. Subroutine X compiles the program whose source is indicated by the 
  359. argument(s) it receives on the PDL, places the object in memory 
  360. starting at c1 (when the top argument is the null string), stores the 
  361. final address in variable 0 [&0$S] and executes the compiled program 
  362. [@@]; the main program calls @X alternating executions of PROG1 and 
  363. PROG2; the compilation of each of these programs overwrites the 
  364. previous one's object program; PROG1 and PROG2 can communicate data 
  365. through the PDL or the workspace.  Notice that PROG1 and PROG2 may in 
  366. turn contain calls to X of the form "PROG3"'A'0$rpGm@Xn0$S, where the 
  367. initial address for the object is now given by variable 0 and is the 
  368. next available address in the compilation area, relative to the 
  369. program containing the predicate @X, and the PDL complement is used to 
  370. stack a copy of the current value of variable 0 (since it will be 
  371. changed by subroutine X); this way overlay trees may be built.
  372.  
  373.     We end this chapter with a discussion of the operators which 
  374. provide the user with an interface to CP/M, the operating system:
  375.  
  376.      Operator            Function performed
  377.  
  378.     _        (Underscore.)  Returns immediately to CP/M.
  379.  
  380.     K        Calls the operating system to execute the 
  381.             function whose number is given by the top PDL 
  382.             argument (which should be two bytes long) 
  383.             with the lower argument copied to register DE 
  384.             (DX on the 8086).  The lower argument remains 
  385.             on the PDL after K is executed, and the top 
  386.             argument is replaced by the resulting value 
  387.             of register A (AL on the 8086) extended to a 
  388.             two-byte value by adjoining a zero upper byte;
  389.             this value usually indicates success or 
  390.             failure in the execution of the CP/M function 
  391.             requested.
  392.  
  393.     k        Identical to K, but lifts both arguments and 
  394.             leaves no A value behind; it is mainly used 
  395.             to request functions for which it is not 
  396.             necessary to check the value of A returned 
  397.             by CP/M.
  398.  
  399.     When the 8086 processor is used, the lower argument of K or k 
  400. may be four bytes long, representing an address and a memory segment 
  401. base; in this case the DS register value is saved, the segment base 
  402. portion of the argument is transferred to DS, the function is 
  403. executed and the previous value of DS is restored.  If the function 
  404. requested is function number 26 (set DMA address), CP/M is called 
  405. first to perform function 51 (set DMA segment base) with the segment 
  406. base indicated by the lower argument (the data segment if this 
  407. argument is two bytes long, the explicit base given if the lenght is 
  408. four) and then the call to CP/M for function 26 is carried out.
  409.  
  410.     Not all CP/M functions require a value in DE (or DX); for 
  411. those functions not needing it the PDL must still contain the 
  412. corresponding two-byte argument in its place, 0 is recommended. 
  413.  
  414.     The use of operators K and k requires a thorough knowledge of 
  415. the operation of CP/M function calls (for example, CP/M must be 
  416. requested to open a file before reading from it, or to close a file 
  417. used for writing in order to update the disk's directory and hence be 
  418. able to access the data later, etc.), however, the discussion of all 
  419. possible variants is beyond the scope of this book, so we refer the 
  420. reader to the bibliography given at the end.  We limit ourselves here 
  421. to giving a list of possible functions and illustrating the use of 
  422. the more important ones.
  423.  
  424.     In the following table, "Num" is the value which the top 
  425. argument must have, "DE" is the kind of datum the lower argument 
  426. should be and "Value" is the value K returns as top argument.  A dash 
  427. in column "DE" indicates that the argument is not used (although both 
  428. K and k require something in its place, usually a zero) and a dash in 
  429. the "Value" column indicates that no specific value is returned in A 
  430. (or AL) and hence the value left by K has no significance.
  431.  
  432.     As regards the abbreviations used in the table, "char" 
  433. represents a character (to be written, if under "DE"; read if under 
  434. "Value"), "FCB" represents the address of a file control block which 
  435. can be created as shown in Chapter 3 or at the beginning of this 
  436. chapter, "stat" indicates the datum contains a byte with the status 
  437. referred to by the corresponding function, "buf" is the address of
  438. a buffer to be used for data transfer, "DMA" is the address of a 
  439. 128-byte buffer to be used in operations to be subsequently performed 
  440. on disk files, "id" is a disk identifier (0 for disk A, 1 for disk B, 
  441. etc.) and "ind" means the returned value indicates the success or 
  442. failure of the function.  The number 80 or 86 next to the function 
  443. number means that line is applicable to the version of CP/M for the 
  444. 8080 or 8086, respectively.
  445.  
  446.  
  447.               TABLE I.  CP/M Functions
  448. =====================================================================
  449.  Num            Function         DE           Value
  450. =====================================================================
  451.   0        System reset             -         -
  452.   1        Read from console         -        char
  453.   2        Write to console        char         -
  454.   3        Read from reader         -        char
  455.   4        Write to punch            char         -
  456.   5        Write to printer        char         -
  457.   6 (80)    Read direct from console    255         char or 0
  458.   6 (80)    Write direct to console        char         -
  459.   6 (86)    Read direct from console    255        char
  460.   6 (86)    Read console status        254        stat
  461.   6 (86)    Write direct to console        char         -
  462.   7        Read I/O byte             -        stat
  463.   8        Write I/O byte            stat         -
  464.   9        Write string to console        buf         -
  465.  10        Read string from console    buf         -
  466.  11        Read console status         -        stat
  467.  12        Read version number         -        ind
  468.  13        Reset disk system         -         -
  469.  14        Select disk            id         -
  470.  15        Open file            FCB        ind
  471.  16        Close file            FCB        ind
  472.  17        Search for first instance    FCB        ind
  473.  18        Search for next instance     -        ind
  474.  19        Delete file            FCB        ind
  475.  20        Read a sector sequentially    FCB        ind
  476.  21        Write a sector sequentially    FCB        ind
  477.  22        Make file            FCB        ind
  478.  23        Rename file            FCB        ind
  479.  24        Read logged disk vector         -        stat
  480.  25        Read logged in disk id         -        id
  481.  26        Set DMA address            DMA         -
  482.  28        Write protect disk         -         -
  483.  30        Set file attributes        FCB        ind
  484.  32        Get user code            255        ind
  485.  32        Set user code               0 to 15         -
  486.  33        Read random            FCB        ind
  487.  34        Write random            FCB        ind
  488.  35        Compute file size        FCB         -
  489.  36        Set random record        FCB         -
  490.  37 (86)    Reset selected disks        stat         -
  491.  40 (86)    Write random with zero fill    FCB        ind
  492.  50 (86)    Direct BIOS call        buf        ind
  493. =====================================================================
  494.  
  495.     As an example of K and k usage, assume FCBs have been 
  496. created by means of subroutines M, C and F shown earlier in this 
  497. chapter.  Then, the following subroutines can be used to open, close, 
  498. make, read and write the files described by the FCBs.
  499.  
  500.     [set DMA buffer at absolute address 128]
  501.     ('080'H 26k;) h
  502.  
  503.     [delete file if present]
  504.     (@h $r 19k;) g
  505.  
  506.     [open file or create it]
  507.     (@h $r 15K (255= 22K 255= "Directory full"T_;;) LL;) e
  508.  
  509.     [open file or report absence]
  510.     (@h $r 15K (255= ^11G T ": Not found"T_;;) LL;) f
  511.  
  512.     [open for reading file denoted by variable 30,
  513.      open for writing file denoted by variable 31]
  514.     (30@f 31@g 31@e;) G
  515.  
  516.     [write 128  workspace bytes to the output file [var. 31],
  517.      false if less then 128 bytes in workspace]
  518.     (Jj 26%EZD 0; 128a qL 26k 31$r
  519.         21K(0= L;
  520.             1= "Directory full"T_;
  521.                "Disk full"T_)
  522.         D'.'T;) p
  523.  
  524.     [write workspace from p0 to p1 to the output file]
  525.     (jJ < (@p '.'=: 0=: L;) Zz>;) P
  526.  
  527.     [append a sector from the input file [var. 30], 
  528.      false when there is no more data to read]
  529.     (128(e) "WS full"T_; qL 26k 30$r 20K 0=L; DLL) y
  530.  
  531.     [empty workspace to the output file, copying what is
  532.      left of the input file, and close the output file]
  533.     (@p '.'=: L@y: (@p '.': 0=; e 26%(f:;) @p L; L;)
  534.      31 $r 16k;) H
  535.  
  536.     These subroutines could be a part of some program that reads 
  537. from the input file to the workspace with @y and writes the processed 
  538. data to the output file with @P; a call to subroutine H at the end 
  539. would ensure that the output file is properly closed; the one byte 
  540. value 26 [26%] used by H to fill the last sector of the output file 
  541. is the ASCII character control-Z used by CP/M to signal the end of 
  542. data in an ASCII text file.
  543.  
  544.  
  545.  
  546.         Chapter 6.  Operation of REC and User-supplied
  547.                 Extensions
  548.  
  549.     The execution of REC for running programs interactively is 
  550. initiated by a command line which simply contains the name of the 
  551. desired REC compiler (which may be REC80, REC80, REC80F or REC86F, 
  552. depending on the processor used and whether floating point arithmetic 
  553. is desired).  If a command line containing only, say, REC80F is given 
  554. to CP/M, execution begins with the following message displayed on the 
  555. console (REC80 produces a similar display):
  556.  
  557.             REC(8080)/ICUAP
  558.          Universidad Autonoma de Puebla
  559.                 [date]
  560.  
  561.          CPL ccccc
  562.          PDL ppppp
  563.          WS  wwww
  564.          Stk ssss
  565.  
  566.          REC80F>
  567.  
  568.     ICUAP means "Institute of Sciences of the Autonomous 
  569. University of Puebla", [date] is the date of the REC version being 
  570. executed, ccccc, ppppp, wwww and ssss are decimal numbers indicating 
  571. the sizes in bytes of the areas available for compilation, pushdown 
  572. list, workspace and machine stack, respectively.  (When REC86 or 
  573. REC86F are executed, additional data in hexadecimal is displayed 
  574. giving the segment base and length for each of the four memory 
  575. segments used by these compilers.)
  576.  
  577.     "REC80F>" in the above example is the prompt indicating that 
  578. REC is ready to read and execute a program.  The program may be 
  579. entered in one or more lines terminated by carriage returns (ASCII 
  580. CR); REC starts execution of the compiled program as soon as it 
  581. recognizes the final right parenthesis or brace.  When entering 
  582. programs in this manner, care has to be taken to ensure that all 
  583. parentheses, braces, brackets and quotation marks (single and double 
  584. quotes) are correctly balanced; this is why the interactive execution 
  585. of REC is only recommended for testing simple programs or program 
  586. fragments.
  587.  
  588.     As stated in Chapter 3, the execution of REC may also include 
  589. additional data on the command line, in which case REC takes the 
  590. first paramater on the command line tail to be the name of a file 
  591. containing the program whose compilation and execution is desired; if 
  592. the given name does not contain an explicit extension, the extension 
  593. REC is assumed, so that the command lines
  594.  
  595.         REC80 EXAMPLE
  596.  
  597.         REC80 EXAMPLE.REC
  598.  
  599. produce identical results.  When REC is executed in this manner, no 
  600. display occurs on the console other than what the compiled REC 
  601. program itself produces; when this program's execution ends, REC 
  602. returns control of the computer to CP/M.  If the file named on the 
  603. command line does not exist, REC returns to CP/M with no further 
  604. indication of the error.
  605.  
  606.     One letter of the ASCII alphabet, X, has been set aside to 
  607. provide access to user-defined operators (other than those defined as 
  608. subroutines in REC).  The compilation of X requires that it be followed 
  609. by a character that becomes a part of the calling sequence generated by 
  610. the compiler (in the style of @x); this character is analyzed by the 
  611. run-time subroutine provided by the user to identify the particular 
  612. operator whose execution is desired.  Specifically, Xa is compiled as an 
  613. operator, with the following calling sequence:
  614.  
  615.         CALL    LIBO
  616.         DB    'a'
  617.  
  618.     The user-written extension must contain the entry point LIBO 
  619. (which in the case of REC80 and REC80F must appear in an ENTRY 
  620. directive if an assembler like Microsoft's M80 is used), and 
  621. this program must be relinked with the rest of the REC compiler 
  622. (reassembled in case one uses ASM86 to assemble REC86 or REC86F).
  623. Further on an example is given of the basic code required for 
  624. implementing operator X.
  625.  
  626.     The REC80 source program is divided into five modules:
  627.  
  628.     - REC80, which contains the compiling routines,
  629.     - PDL80, which contains the PDL predicates and operators,
  630.     - MKV80, which contains the workspace operators and 
  631.          predicates,
  632.     - LIB80, which contains the definition for predicate x, and
  633.     - FXT80, which contains tables, the CP/M interface and the 
  634.          initializing routine; all other modules must precede
  635.          this one in memory.
  636.  
  637.     Once M80 has assembled the above four modules, the executable 
  638. module REC80.COM is produced by the command line
  639.  
  640.     L80 MKV80,PDL80,REC80,LIB80,FXT80/E,REC80/N
  641.  
  642.     REC80F consists of seven modules, to wit,
  643.  
  644.     - FLT80F, which contains binary-ASCII and ASCII-binary 
  645.           conversion routines,
  646.     - ATH80F, which contains the arithmetic operators, and
  647.  
  648. REC80F, PDL80F, MKV80F, LIB80F and FXT80F, which contain functions similar
  649. to the analogously named REC80 modules.
  650.  
  651.     Analogously to REC80, the assembled modules may be linked 
  652. with L80 to create a REC80F executable module with the following 
  653. command line, which generates the file REC80F.COM:
  654.  
  655.     L80 MKV80F,PDL80F,ATH80F,FLT80F,REC80F,LIB80F,FXT80F/E,REC80F/N
  656.  
  657.     Notice that in this case it is also required to place module 
  658. FXT80F last.
  659.  
  660.     For the 8086 versions, REC86 and REC86F, we have used 
  661. CP/M-86's assembler ASM86.  Even though the source programs for these 
  662. compilers are kept in 5 and 7 separate modules, respectively, ASM86 
  663. assembles all modules together directed by an additional small module 
  664. containing only INCLUDE directives.  Thus, to assemble REC86, ASM86 
  665. is requested to assemble a file REC86.A86, containing the following:
  666.  
  667.             CSEG
  668.             INCLUDE PDL86.A86
  669.             INCLUDE MKV86.A86
  670.             INCLUDE REC86A.A86
  671.             INCLUDE LIB86.A86
  672.             INCLUDE FXT86.A86
  673.             END
  674.  
  675.     The source module containing the compilation routines of REC 
  676. is now called REC86A; this is done so that ASM86 will produce, from 
  677. the assembly of the above small program, a file named REC86.H86, from 
  678. which the executable module REC86.CMD can be generated by GENCMD, a 
  679. utility program provided by CP/M-86.  The computer system on which 
  680. REC86 was developed has 256kbytes of memory, of which 192k are 
  681. contiguous and start at address 00000H and the remaining 64k start at 
  682. address F0000H.  The command line we have used to generate REC86.CMD 
  683. is the following:
  684.  
  685. GENCMD REC86 CODE[M1000] DATA[M1000] EXTRA[A0F000,M0FFF] STACK[M0C00]
  686.  
  687. which allocates 64k for the code segment (which includes the compiler 
  688. itself), 64k for the data segment (including REC's PDL and the 
  689. compilation, variable and subroutine tables), 64k for the extra 
  690. segment (containing the workspace) and 48k for the 8086's machine 
  691. stack.  The remaining 16k are used by CP/M-86.
  692.  
  693.     To end our description of the standard REC compilers, we note 
  694. that the assembly of REC86F is similar to that of REC86, but in this 
  695. case the small module whose assembly is requested to AASM86 is called 
  696. REC86F.A86 and contains the following lines:
  697.  
  698.             CSEG
  699.             INCLUDE PDL86F.A86
  700.             INCLUDE MKV86F.A86
  701.             INCLUDE ATH86F.A86
  702.             INCLUDE FLT86F.A86
  703.             INCLUDE REC86FA.A86
  704.             INCLUDE LIB86F.A86
  705.             INCLUDE FXT86F.A86
  706.             END
  707.  
  708.     The generation of the executable module REC86F.CMD is 
  709. accomplished by executing GENCMD with a command line entirely 
  710. analogous to the one given for REC86.
  711.  
  712.     Suppose now that a user wants to add to REC80 the operators
  713. X0, X1, X2, X3 and X4, and that any other predicate of the form Xa 
  714. should effect an immediate return.  The user would then provide a new 
  715. module, say UOP80.MAC, which would contain the following program (in 
  716. which the explicit processes represented by the five new operators
  717. are omitted): 
  718.  
  719.     ENTRY    LIBO    ;Declare LIBO to be an entry point
  720. ;
  721. LIBO:    POP    H    ;Pick up the return addr (calling seq. pointer)
  722.     MOV    A,M    ;Copy the character from the calling sequence
  723.     INX    H    ;Get the actual return address 
  724.     PUSH    H    ;push it back on the stack
  725.     CPI    '5'    ;Is the char. less than or equal to ASCII 5?
  726.     RNC        ;exit if not
  727.     SUI    '0'    ;Is the char. greater than or equal to 0?
  728.     RC        ;exit if not
  729. ;
  730. ;    Notice that register A now contains a value between 0 and 4
  731. ;
  732.     ADD    A    ;Multiply A by 2,
  733.     MOV    C,A    ;pass on to C,
  734.     MVI    B,0    ;extend to 2 bytes with a zero in B.
  735.     LXI    H,TAB    ;The origin in the table of addresses
  736. ;            ;of subroutines X0 to X4
  737.     DAD    B    ;added to BC gives the address in the table
  738. ;            ;of the desired subroutine's entry address
  739.     MOV    E,M    ;which we copy to DE
  740.     INX    H
  741.     MOV    D,M
  742.     XCHG        ;pass on to HL
  743.     PCHL        ;and we jump to it.
  744. ;
  745. TAB:    DW    ZERO    ;ZERO is the address of the subroutine for X0
  746.     DW    ONE    ;ONE is X1's entry point
  747.     DW    TWO    ; and so forth
  748.     DW    THREE
  749.     DW    FOUR
  750. ;
  751. ZERO:    ...        ;Here we insert the instructions which carry
  752. ;            ;out the function associated with X0,
  753. ;
  754. ONE:    ...        ;In a similar manner for X1,
  755. ;
  756. TWO:    ...        ;X2,
  757. ;
  758. THREE:    ...        ;X3
  759. ;
  760. FOUR:    ...        ;and X4.
  761. ;
  762.     END
  763.  
  764.     This module is assembled with M80 and linked to make an 
  765. executable module as follows:
  766.  
  767.     L80 UOP80,MKV80,PDL80,REC80,LIB80,FXT80/E,UREC80/N
  768.  
  769. where the new executable module's name is UREC80.COM.
  770.  
  771.     Finally, we mention the predicate xa, which provides a way
  772. to call predicates added to a REC program using operator C after
  773. its execution has begun.  xa operates in a manner similar to @a
  774. in the sense that it calls a predicate whose address is in a table
  775. indexed by the ASCII character a; the difference is that @ always
  776. refers to a fixed table, whereas the table referenced by x may be
  777. changed.
  778.  
  779.     x@ is a predicate which takes, like @@, an argument from
  780. the PDL; if it is a single byte, it is assumed to be an ASCII 
  781. character to be used as an index to the current table (for instance,
  782. '$'x@ has the same effect as x$).  However, if the PDL argument is
  783. a two-byte value, it must be the address of a new table (whose 
  784. indices are the ASCII characters exclamation point (!) through
  785. tilde (~)), from which predicate x will take execution addresses
  786. in subsequent uses, and until a new table is given by a further
  787. execution of x@ with a two-byte argument.
  788.  
  789.     At the start of REC's execution, predicate x refers to the
  790. same table as @, so that xa and @a produce the same result.  Once
  791. the table referenced by x is changed, it is possible to reset it
  792. to the initial state by the use of '!'$x@, since '!'$ places on
  793. the PDL the address of the portion of the table of subroutines
  794. (called by @) starting at character "!".  Note that the mechanism
  795. whereby braces ({ and }, see Chapter 1) deactivate external definitions
  796. to activate internal ones only affects the table used by @ and not
  797. that referenced by x, if the latter table is different from the former.
  798.  
  799.     This predicate has been used in the CONVERT compiler to
  800. effect automatic inclusion of programs from a library when execution
  801. of a Convert program is begun.
  802.