home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol164 / fxt80.mac < prev    next >
Encoding:
Text File  |  1984-04-29  |  27.4 KB  |  1,031 lines

  1.  
  2. ;    =======================================================
  3. ;    REC module containing RAM storage, I/O programs, main
  4. ;    program, and the directory. The complete set of modules
  5. ;    comprises REC80.MAC, PDL80.MAC, MKV80.MAC, RECLIB.MAC, and
  6. ;    FXT80.MAC.  RECLIB.MAC may be omitted if the operator X
  7. ;    isn't used, and must be substituted by another module
  8. ;    if the collection of subroutines to be called by X is
  9. ;    to be changed.
  10. ;
  11. ;    FXT80.MAC contains the following REC operators and
  12. ;    predicates:
  13. ;
  14. ;        C    compile a REC expression
  15. ;        i    input from designated port
  16. ;        k    call CP/M without residue
  17. ;        K    call CP/M, preserve FCB, return value
  18. ;        o    output from designated port
  19. ;        R    read one character from console
  20. ;        t    type message given header
  21. ;        T    type argument on PDL
  22. ;        W    write argument on LST:
  23. ;        x    execute REC subroutine
  24. ;        `    test if a character waits at keyboard
  25. ;
  26. ;    REC version released during the 1980  Summer School of
  27. ;    the Microcomputer Applications Group of the I.C.U.A.P.
  28. ;
  29. ;             FXT80  -  Copyright (C) 1980
  30. ;            Universidad Autonoma de Puebla
  31. ;          49 Poniente 1102 -  Puebla, Puebla, Mexico
  32. ;             All Rights Reserved
  33. ;
  34. ;         [Harold V. McIntosh,  28 August 1980]
  35. ;
  36. ;    1 January 1981 - get address of BIOS vector from rst0
  37. ;    1 January 1981 - protect T with pushes, pops of DE, HL
  38. ;    1 January 1981 - memory reorganization
  39. ;    24 May 1981 - 0000 at bottom of PDL to restrain L
  40. ;    3 March 1982 - rewrite extension as REC - (FGZ)
  41. ;    25 March 1982 - Y is now a predicate
  42. ;    25 April 1982 - C is also a predicate, modified for {}'s
  43. ;    20 May 1983 - N is numerical comparison predicate
  44. ;    20 May 1983 - h has been withdrawn
  45. ;    28 May 1983 - ~ has been redefined
  46. ;    30 May 1983 - cpin: return to CP/M if file won't open
  47. ;    8 July 1983 - C has object program origin as argument
  48. ;    8 July 1983 - C is an operator
  49. ;    8 July 1983 - c0 defined as lower limit compile area
  50. ;    8 July 1983 - x has been moved from RECLIB.MAC
  51. ;    8 July 1983 - x predicate - to call REC subroutines
  52. ;    9 July 1983 - Buffered CP/M input if no disk file given
  53. ;    14 July 1983 - exchange arguments of W
  54. ;    21 July 1983 - partition available memory on entry
  55. ;    =======================================================
  56.  
  57. ;    Absolute program locations used by CP/M.
  58.  
  59. rst0    equ    0000H
  60. boot    equ    rst0    ;CP/M bootstrap entry point
  61. bios    equ    rst0+1    ;CP/M BIOS reference point
  62. bdos    equ    rst0+5    ;CP/M I-O communication point
  63. emem    equ    rst0+6    ;where effective end of memory is stored
  64.  
  65. tfcb    equ    005CH    ;CP/M file control block
  66. talt    equ    006CH    ;CP/M alternate file name
  67. fsiz    equ    0010H    ;CP/M file name size
  68. tbuf    equ    0080H    ;CP/M disk buffer location
  69. tsiz    equ    0080H    ;CP/M disk buffer size
  70.  
  71. ;    Useful constant.
  72.  
  73. ze    equ    00H
  74.  
  75. ;    Equivalences to other REC subroutines.
  76.  
  77.     ext    noop
  78.     ext    ucl,cucl,narg,oarg
  79.     ext    miuc,mduc,putw,bcld,deld
  80.     ext    skp,req,seq,rer,rr2
  81.     ext    psiz,siz,sng,sing
  82.     ext    left,recrr,onel
  83.  
  84.     ext    recre,emce,emcu,emcv,emcx,ar,nar,inre
  85.  
  86.     ext    twol
  87.  
  88. ;    =======================================================
  89. ;    Programs related to input-output and disk usage.
  90. ;    =======================================================
  91.  
  92. ;    Buffer read routine.
  93.  
  94. pty:    push    h    ;conserve HL
  95.     lhld    rx    ;pointer to read buffer
  96.     mov    a,m    ;fetch byte
  97.     inx    h    ;advance pointer to next byte
  98.     shld    rx    ;update buffer pointer
  99.     pop    h    ;restore HL - preserve all reg pairs
  100.     ret
  101.  
  102. ;    Console character read routine.  Strict CP/M compatible
  103. ;    version, which has characteristics undesirable for some
  104. ;    applications, such as an automatic echo or preemption
  105. ;    of some of the control characters for editing purposes.
  106. ;    When it is used, programs must forego their own echo,
  107. ;    and do their own editing when required.
  108.  
  109. ;chin:    push    h
  110. ;    push    d
  111. ;    push    b
  112. ;    mvi    c,1        ;read from console
  113. ;    call    bdos
  114. ;    pop    b
  115. ;    pop    d
  116. ;    pop    h
  117. ;    ret
  118.  
  119. ;    Version with direct access to CONIN.
  120.  
  121. chin    equ    conin
  122.  
  123. ;    Buffered console character read routine, which is more
  124. ;    practical for use with CP/M.
  125.  
  126. buin:    push    h        ;save 3 register pairs
  127.     push    d        ;
  128.     push    b        ;
  129.     lhld    ry        ;buffer limit
  130.     xchg            ;
  131.     lhld    rx        ;buffer pointer
  132.     mov    a,l        ;check for exhausted buffer
  133.     cmp    e        ;
  134.     jnz    bi5        ;buffer remnant available
  135.     mov    a,h        ;
  136.     cmp    d        ;
  137.     jnz    bi5        ;buffer remnant available
  138.     mvi    c,9        ;(09) write message
  139.     lxi    d,bume        ;REC80 prompt
  140.     call    bdos        ;
  141.     mvi    c,10        ;(0A) buffered read
  142.     lxi    d,tbuf        ;
  143.     call    bdos        ;
  144.     mvi    c,9        ;(09) write message
  145.     lxi    d,crlf        ;CR,LF
  146.     call    bdos        ;
  147.     lxi    h,tbuf+2    ;where the text begins
  148.     shld    rx        ;buffer pointer
  149.     dcx    h        ;
  150.     mov    e,m        ;get occupancy
  151.     mvi    d,0        ;insert leading zero
  152.     dad    d        ;calculate final address
  153.     inx    h        ;plus one more - that's REC style
  154.     shld    ry        ;buffer limit
  155.     lhld    rx        ;buffer pointer
  156. bi5:    mov    a,m        ;pick up the next character
  157.     inx    h        ;ready for another
  158.     shld    rx        ;buffer pointer
  159.     pop    b        ;restore 3 registers
  160.     pop    d        ;
  161.     pop    h        ;
  162.     ret
  163.  
  164. logo:    db    0DH,0AH,'       REC(8080)/ICUAP',0DH,0AH
  165.     db    'Universidad Autonoma de Puebla',0DH,0AH
  166.     db    '      November 20, 1983',0DH,0AH,'$'
  167. bume:    db    0DH,0AH,'REC80> $'
  168. crlf:    db    0DH,0AH,'$'
  169.  
  170. ;    Define the console buffer as the source code reader.
  171.  
  172. bure:    lxi    h,tbuf        ;the disk won't be using its buffer
  173.     mvi    m,tsiz-2    ;define its maximum length
  174.     inx    h        ;text origin is two bytes on
  175.     inx    h        ;
  176.     shld    rx        ;buffer pointer
  177.     shld    ry        ;buffer limit
  178.     lxi    h,buin        ;buffered source from console
  179.     shld    re        ;REC compiler's I-O linkage
  180.     ret
  181.  
  182. ;    Console character out routine.  Strict CP/M compatible
  183. ;    version, which unfortunately makes so many tests and
  184. ;    jumps that it is unsuitable for programs such as the
  185. ;    cursor editor which frequently write a full screen.
  186.  
  187. ;chou:    push    h
  188. ;    push    d
  189. ;    push    b
  190. ;    mvi    c,2        ;write character at console
  191. ;    mov    e,a
  192. ;    call    bdos
  193. ;    pop    b
  194. ;    pop    d
  195. ;    pop    h
  196. ;    ret
  197.  
  198. ;    Version with fast access to conout.
  199.  
  200. chou:    push    b
  201.     mov    c,a
  202.     call    conou
  203.     pop    b
  204.     ret
  205.  
  206. ;    (`)  Test for preesence of waiting character (FALSE if
  207. ;    none waiting).
  208. ;
  209. ;chaw:    mvi    c,11    ;<test for waiting character>
  210. ;    call    bdos    ;
  211. ;    rrc        ;bit 0 holds the relevant information
  212. ;    rnc        ;FALSE return if the bit is zero
  213. ;    jmp    skp    ;TRUE return if it is set
  214.  
  215. ;    Version with fast access to const.  It is required when
  216. ;    the fast chin is used, because CP/M has some internal
  217. ;    buffers which will otherwise distort the results.
  218.  
  219. chaw:    call    const
  220.     rrc
  221.     rnc
  222.     jmp    skp
  223.  
  224. ;    Printer output routine.
  225.  
  226. prou:    push    h
  227.     push    d
  228.     push    b
  229.     mvi    c,5        ;output through LST:
  230.     mov    e,a
  231.     call    bdos
  232.     pop    b
  233.     pop    d
  234.     pop    h
  235.     ret
  236.  
  237. ;    (R)  REC read operator.
  238.  
  239. ucr:    lxi    b,1    ;one byte to be inserted
  240.     call    narg    ;close last arg, verify space
  241.     call    tyin    ;get byte from console input
  242.     mov    m,a    ;store on PDL
  243.     inx    h    ;advance pointer
  244.     shld    py    ;save as terminator
  245.     ret
  246.  
  247. ;    (t) Write indirect operator.  <org,siz,t> prints the
  248. ;    indicated message, leaves no residue.
  249.  
  250. lct:    lhld    px    ;fetch argument pointer
  251.     call    twol    ;move two args to 8080 stack
  252.     pop    d    ;second arg (org) into DE
  253.     pop    h    ;top arg (siz) into HL
  254.     dad    d    ;org+siz=end
  255.     xchg        ;DE=end, HL=org
  256.     jmp    ut1    ;use write cycle in UCT
  257.  
  258. ;    (T)  REC write operator.  <'XXX' T> will write XXX on
  259. ;    the console, leaving it on the PDL.
  260.  
  261. uct:    lhld    py    ;fetch terminal address
  262.     xchg        ;put it in DE
  263.     lhld    px    ;beginning address to HL
  264. ut1:    mov    a,e    ;compare low bytes
  265.     cmp    l    ;
  266.     jnz    ut2    ;don't match, keep writing
  267.     mov    a,d    ;compare high bytes
  268.     cmp    h    ;
  269.     rz        ;they match, we're done
  270. ut2:    mov    a,m    ;get byte out of memory
  271.     push    h    ;the registers DE and HL
  272.     push    d    ;are essential for the loop
  273.     call    tyou    ;send it to typeout
  274.     pop    d    ;recover the saved registers
  275.     pop    h    ;
  276.     inx    h    ;advance pointer
  277.     jmp    ut1    ;repeat
  278.  
  279. ;    (W)  REC print operator.  <org, siz, W> will print the
  280. ;    indicated text on the list device, and then erase its
  281. ;    arguments.
  282.  
  283. ucw:    lhld    px    ;pointer to arguments
  284.     call    twol    ;2 args from PDL to 8080 stack
  285.     pop    h    ;place text origin in HL
  286.     pop    d    ;place length in DE
  287. uww:    mov    a,e    ;check for zero length
  288.     ora    d    ;by superposing length bytes
  289.     rz        ;no more to print
  290.     mov    a,m    ;fetch a byte
  291.     push    h    ;we need to be sure that DE and HL are
  292.     push    d    ;preserved whatever the print routine
  293.     call    prou    ;send it to printer
  294.     pop    d    ;recover HL
  295.     pop    h    ;and DE
  296.     dcx    d    ;diminish count
  297.     inx    h    ;advance pointer
  298.     jmp    uww    ;repeat
  299.  
  300. ;    (i)  Input from designated port.  <port, i> leaves
  301. ;    <port, byte> so that after disposing of <byte>, <port>
  302. ;    can be reused.
  303.  
  304. lci:    lhld    px    ;get pointer to top argument on PDL
  305.     mov    a,m    ;only the low order byte matters
  306.     sta    qi    ;place it in teme IN instruction
  307.     lxi    b,1    ;we're only going to read one byte
  308.     call    narg    ;prepare a place for it on the PDL
  309.     call    qin    ;execute the captive IN instruction
  310.     mov    m,a    ;storing the incoming byte on the PDL
  311.     inx    h    ;always ready for the next byte
  312.     shld    py    ;close off the argument
  313.     ret        ;and we're through
  314.  
  315. ;    (o) Output from designated port  -  <port, byte, o>
  316. ;    leaves <port>, facilitating multiple OUTs through the
  317. ;    same port.
  318.  
  319. lco:    lhld    px    ;pointer to last argument - output byte
  320.     mov    b,m    ;tuck it into register b
  321.     call    ucl    ;erase the top argument
  322.     mov    a,m    ;HL points to next argument - get it
  323.     sta    qo    ;store in tame OUT instruction
  324.     mov    a,b    ;output must be from accumulator
  325.     jmp    qou    ;execute the prepared OUT instruction
  326.  
  327. ;    =======================================================
  328. ;
  329. ;    Communication with CP/M takes two forms:  <FCB, n, K>
  330. ;    which leaves <FCB, coDe> on the pushdown list, or else
  331. ;    <FCB, n, k> which leaves nothing on the pushdown list.
  332. ;    In either case - FCB is a two-byte parameter, usually
  333. ;    the address of the file control block - but it could
  334. ;    also be a DMA address or sometimes even null for the
  335. ;    sake of uniformity.  Approximately thirty options are
  336. ;    available which are numbered serially, indicated by the
  337. ;    argument n.  The difference between K and k is that the
  338. ;    former conserves the parameter FCB for possible use by
  339. ;    a subsequent CP/M call, and reports a result in the
  340. ;    one-byte result <code>.  This could be the character
  341. ;    read by an input routine or an error code for the disk
  342. ;    routines.
  343. ;
  344. ;    The options are:
  345. ;
  346. ;    num    function        "FCB"    "code"
  347. ;    ---    --------        -----    ------
  348. ;
  349. ;     0    system reset        -    -
  350. ;     1    read console        -    char
  351. ;     2    write console        char    -
  352. ;     3    read reader        -    char
  353. ;     4    write punch        char    -
  354. ;     5    write list        char    -
  355. ;     6    -            -    -
  356. ;     7    read i/o stat        -    stat
  357. ;     8    write i/ stat        stat    -
  358. ;     9    print buffer        buffer    -
  359. ;    10    read buffer        buffer    -
  360. ;    11    console status    -    stat
  361. ;
  362. ;    12    lift disk head        -    -
  363. ;    13    init disk only        -    -
  364. ;    14    select disk        disk    -
  365. ;    15    open file        fcb    code
  366. ;    16    close file        fcb    code
  367. ;    17    search once        fcb    code
  368. ;    18    search again        fcb    code
  369. ;    19    delete file        fcb    code
  370. ;    20    read 1 record        fcb    code
  371. ;    21    write 1 record        fcb    code
  372. ;    22    create file        fcb    code
  373. ;    23    rename file        fcb    code
  374. ;    24    read login        -    logv
  375. ;    25    read disklog        -    disk
  376. ;    26    set DMA address        dma    -
  377. ;    27    read bitmap        -    -
  378. ;
  379. ;    Fuller details of all the CP/M options and the way they
  380. ;    function can be obtained through consulting Digital
  381. ;    Research's manuals for CP/M, especially their "CP/M
  382. ;    Interface Guide."
  383. ;
  384. ;    =======================================================
  385.  
  386. ;    (K)  Set up communication with CP/M - top into BC,
  387. ;    next into DE.  Preserve next, call BDOS, (Aze) into
  388. ;    top.
  389.  
  390. cpm:    lhld    px    ;fetch pointer to top argument
  391.     mov    c,m    ;load C from low byte
  392.     inx    h    ;next byte
  393.     mov    b,m    ;load B from high byte
  394.     lhld    px    ;pointer to top argument again
  395.     dcx    h    ;high byte, pointer to prev arg
  396.     mov    d,m    ;load up DE with high byte
  397.     dcx    h    ;low byte, pointer to prev arg
  398.     mov    e,m    ;finish loading DE
  399.     xchg        ;pointer into HL
  400.     mov    e,m    ;low byte of under argument
  401.     inx    h    ;advance pointer
  402.     mov    d,m    ;high byte of under argument
  403.     call    bdos    ;call BDOS with args in BC, DE
  404.     lhld    px    ;pointer to top argument again
  405.     mov    m,a    ;save low byte from A
  406.     inx    h    ;on to high byte
  407.     mvi    m,ze    ;make high byte a zero
  408.     ret
  409.  
  410. ;    (k)  Call to CP/M without any value returned.
  411.  
  412. cpml:    call    bcld    ;load top arg into BC, lift it
  413.     call    deld    ;load next arg into DE, lift it too
  414.     jmp    bdos    ;execute indicated operation
  415.  
  416. ;    -------------------------------------------------------
  417. ;    Disk input-output routine working through CP/M.
  418. ;    -------------------------------------------------------
  419.  
  420. ;    Set up a file control block with a given file name and
  421. ;    the default extension REC.  The pushdown list contains
  422. ;    the disk unit designation, then by the filename without
  423. ;    any extension. No protection is afforded against an
  424. ;    overly long file name, a nonexistent disk, or the like.
  425. ;    Some errors of this type must be caught by CP/M since
  426. ;    REC cannot know such things as the exact number of disk
  427. ;    drives that there will be.
  428.  
  429. diin:    mvi    b,21H        ;FCB requires 33 bytes
  430.     lxi    h,tfcb        ;use CP/M's transient FCB
  431.     mvi    a,00H        ;fill it with zeroes
  432. di1:    mov    m,a        ;loop for block zero
  433.     inx    h        ;advance pointer
  434.     dcr    b        ;reduce count
  435.     jnz    di1        ;repeat until count vanishes
  436.     mvi    b,8        ;filename field is 8 bytes long
  437.     lxi    h,tfcb+1    ;field begins at second byte
  438.     mvi    a,' '        ;fill it with blanks
  439. di2:    mov    m,a        ;loop for block of blanks
  440.     inx    h        ;advance pointer
  441.     dcr    b        ;reduce count
  442.     jnz    di2        ;repeat until count vanishes
  443.     mvi    m,'R'        ;place 'REC' in extension field
  444.     inx    h        ;
  445.     mvi    m,'E'        ;
  446.     inx    h        ;
  447.     mvi    m,'C'        ;
  448.     lhld    px        ;fetch pointer to top argument
  449.     mov    a,m        ;load disk unit designator
  450.     sui    '@'        ;normalize to uppercase letters
  451.     sta    tfcb        ;store it in file control block
  452.     call    ucl        ;pop top argument
  453.     lhld    px        ;fetch pointer to file name
  454.     xchg            ;place it in DE for source
  455.     lhld    py        ;end of file name
  456.     call    siz        ;place py - px in BC
  457.     lxi    h,tfcb+1    ;destination origin
  458.     call    miuc        ;move by increment until count
  459. cpin:    lda    tfcb+1
  460.     cpi    ' '
  461.     jz    boot        ;no file given, so quit
  462.     mvi    c,15        ;<open file>
  463.     lxi    d,tfcb        ;file control block
  464.     call    bdos        ;
  465.     cpi    0FFH        ;check for error
  466.     jz    boot        ;don't hang system; so quit instead
  467.     lxi    h,tbuf        ;origin of CP/M's sector buffer
  468.     shld    rx        ;initial address of pseudotty
  469.     shld    ry        ;provoke disk read
  470.     ret
  471.  
  472. ;    Read from disk buffer, replenish buffer when empty.
  473.  
  474. dire:    push    h        ;save 3 8080 register pairs
  475.     push    d        ;
  476.     push    b        ;
  477.     lhld    ry        ;pointer to end of buffer
  478.     xchg            ;place in DE
  479.     lhld    rx        ;pointer to current byte
  480.     call    seq        ;skip if equal
  481.     jmp    di5        ;still have bytes in the buffer
  482.     mvi    c,20        ;<read next record>
  483.     lxi    d,tfcb        ;file control block
  484.     call    bdos        ;
  485.     lxi    h,tbuf+tsiz    ;end of buffer
  486.     shld    ry        ;store it in ry
  487.     lxi    h,tbuf        ;beginning of buffer
  488.     shld    rx        ;store it in rx
  489. di5:    mov    a,m        ;common continuation
  490.     inx    h        ;byte in acc, advance pointer
  491.     shld    rx        ;store position of next byte
  492.     pop    b        ;replace 3 register pairs
  493.     pop    d        ;
  494.     pop    h        ;
  495.     ret
  496.  
  497. ;    Stack the secondary file name on the 8080's PDL.
  498.  
  499. pualt:    mvi    b,fsiz        ;load size of file name
  500.     lxi    d,talt        ;load origin of secondary name
  501.     pop    h        ;put the return address in HL
  502. pual:    ldax    d        ;load acc from FCB
  503.     push    psw        ;transfer to 8080 stack
  504.     inx    d        ;advance pointer
  505.     dcr    b        ;reduce count
  506.     jnz    pual        ;repeat until count vanishes
  507.     pchl            ;return to addr stored in HL
  508.  
  509. ;    ================
  510. ;    = main program =
  511. ;    ================
  512.  
  513. main::    lhld    emem        ;BDOS entry point is end of memory
  514.     sphl            ;define stack (end of memory)
  515.     lxi    d,-800H        ;reserve space for stack
  516.     dad    d        ;
  517.     mvi    m,0        ;0000 as barrier for '>'
  518.     dcx    h        ;
  519.     mvi    m,0        ;
  520.     dcx    h        ;
  521.     shld    p4        ;end of workspace
  522.     xchg            ;
  523.     lxi    h,bmem        ;beginning of free memory
  524.     shld    c0        ;compile area lower limit
  525.     shld    c1        ;compile area pointer
  526.     mov    a,e        ;calculate amount of available memory
  527.     sub    l        ;
  528.     mov    e,a        ;
  529.     mov    a,d        ;
  530.     sbb    h        ;
  531.     mov    d,a        ;
  532.     mvi    b,3        ;right shift 3 = divide by 8
  533. majn:    mov    a,d        ;shift loop
  534.     ora    a        ;
  535.     rar            ;
  536.     mov    d,a        ;
  537.     mov    a,e        ;
  538.     rar            ;
  539.     mov    e,a        ;
  540.     dcr    b        ;
  541.     jnz    majn        ;
  542.     dad    d        ;assign 1/2 memory to compile area
  543.     dad    d        ;
  544.     dad    d        ;
  545.     dad    d        ;
  546.     shld    c2        ;compile area upper limit
  547.     mvi    m,0        ;store 0000 as barrier to 'L'
  548.     inx    h        ;
  549.     mvi    m,0        ;
  550.     inx    h        ;
  551.     shld    px        ;beginning of PDL
  552.     shld    py        ;with null argument
  553.     dad    d        ;assign    3/8 of memory to PDL
  554.     dad    d        ;
  555.     dad    d        ;
  556.     shld    pz        ;upper limit of PDL
  557.     shld    p0        ;lower limit of workspace
  558.     shld    p1        ;initially filled with null text
  559.     shld    p2        ;workspace gets 1/8+roundoff of memory
  560.     shld    p3        ;
  561.  
  562. ;    Up to this point the memory has been partitioned between the
  563. ;    compile area, pushdown list, workspace, and 8080 stack. By
  564. ;    changing the distribution, it might be possible to accomodate
  565. ;    the memory balance of a specific application better.
  566.  
  567.     lxi    d,0003H        ;length of one jump instruction
  568.     lhld    bios        ;BIOS vector reference point
  569.     dad    d        ;
  570.     shld    cnst        ;jump to const = bios(1)
  571.     dad    d        ;
  572.     shld    cnin        ;jump to conin = bios(2)
  573.     dad    d        ;
  574.     shld    cnou        ;jmp to conout = bios(3)
  575.     lda    tfcb+1        ;if no disk, source from console
  576.     cpi    ' '        ;
  577.     jz    tylo        ;type logo - including version date
  578.     call    pualt        ;save secondary file name
  579.     call    cpin        ;open disk file for REC program
  580.     lxi    h,dire        ;REC input through disk
  581.     shld    re        ;REC compiler's I-O linkage
  582.     call    inre        ;initialize REC compiler RAM
  583.     call    emcx        ;compile the program file
  584.     mvi    b,fsiz        ;length of filename
  585.     lxi    d,tfcb+fsiz    ;end of secondary filename
  586.     pop    h        ;emcx leaves execution addr on stack
  587. poal:    dcx    d        ;restoration loop runs backward
  588.     pop    psw        ;
  589.     stax    d        ;
  590.     dcr    b        ;
  591.     jnz    poal        ;
  592.     push    h        ;put execution address back on stack
  593.     call    emcu        ;execute the program file
  594.     jmp    boot        ;return to CP/M if false
  595.     jmp    boot        ;or even if it was true
  596.  
  597. tylo:    mvi    c,9        ;(09) write message
  598.     lxi    d,logo        ;'UAP ...' logo, version date
  599.     call    bdos        ;
  600. nodi:    call    bure        ;initialize for console buffer
  601.     call    inre        ;initialize REC's RAM area
  602.     call    emcx        ;compile a program
  603.     call    emcu        ;execute it
  604.     jmp    nodi        ;no-disk loop
  605.     jmp    nodi        ;no-disk loop
  606.  
  607. ;    (C) REC compiling operator, which obtains the object code
  608. ;    origin and the source code address from the pushdown list,
  609. ;    in the form <'object', 'source', C>.
  610. ;
  611. ;    <'', 'source', C> will use the current value of c1 for the
  612. ;    object code origin, and would be the alternative normally
  613. ;    selected by someone who did not want to do his own memory
  614. ;    management. If c0 .LE. 'object' .LE. c2, c1 will be set to
  615. ;    'object', very likely disrupting the compile area; thus any
  616. ;    origin must be specified with care. However, if the origin
  617. ;    is taken from a value returned by C, all will work smoothly,
  618. ;    allowing for the automatic erasure of a subroutine once it
  619. ;    has been executed and is no longer needed. Likewise there
  620. ;    will be no conflict if a compile area is taken from the
  621. ;    pushdown list using the operator c.
  622. ;
  623. ;    Ignoring 'object' for the moment, the various options for
  624. ;    just <'source', C> are:
  625. ;
  626. ;          ''C        input program from console
  627. ;        'file' 'D' C    take <file.rec> from disk D
  628. ;           pC        pushdown list
  629. ;           qC        workspace
  630. ;        <org,siz,C>        memory from address org onward
  631. ;
  632. ;    In general, if the 'source' argument is of length zero, then
  633. ;    the console is the source, while if it is of length one the
  634. ;    named disk is the source [@=current disk, A, B, ... up to the
  635. ;    system's limit], and finally if the argument has length 2, the
  636. ;    combination of <org, siz> from the memory applies.  It is the
  637. ;    programmer's responsibility to avoid nonexistent memory, disk
  638. ;    units, and the like.
  639. ;
  640. ;    Two values are returned to the pushdown list by C, namely
  641. ;    <'end', 'origin'>, which define the memory occupied by the
  642. ;    subroutine just compiled, and which will be needed for the
  643. ;    subsequent usage of the subroutine. For example, a series
  644. ;    of subroutines can be compiled by using the 'end' of one as
  645. ;    'object' for the next: <'org' 'S1' Cm 'S2' Cm ...> leaving
  646. ;    their execution addresses on the complementary pushdown list,
  647. ;    where they may be recovered by the operator n. In practice,
  648. ;    they would probably be defined as they were compiled using
  649. ;    <... C 'X'$S ... @X>, or perhaps they would be executed and
  650. ;    discarded using <... CxL>. Housekeeping is important when
  651. ;    subroutines are to be discarded during program execution.
  652. ;    If the origin of a subroutine is saved, it may be reused
  653. ;    which implies that the space which it and any following
  654. ;    subroutines occupied may also be reused.
  655.  
  656. ucc:    call    psiz    ;fetch size of top argument
  657.     mov    a,c    ;test for zero bytes
  658.     ora    b    ;by jamming BC into accumulator
  659.     jz    uc2    ;zero means console
  660.     dcx    b    ;test for one byte
  661.     mov    a,c    ;by jamming BC into accumulator
  662.     ora    b    ;
  663.     jz    uc1    ;one means disk designation
  664.     dcx    b    ;verify that we've got two bytes
  665.     mov    a,c    ;again jamming BC into A
  666.     ora    b    ;
  667.     jnz    rer    ;no provision for other than 1, 2 bytes
  668.     lxi    h,pty    ;setup readin from pseudoteletype
  669.     shld    re    ;REC compiler's I-O linkage
  670.     call    bcld    ;size into BC
  671.     mov    e,m    ;HL is uncovered px
  672.     inx    h    ;
  673.     mov    d,m    ;
  674.     xchg        ;
  675.     shld    rx    ;origin of REC source code
  676.     dad    b    ;length of source code
  677.     shld    ry    ;end of source code
  678.     jmp    uc4
  679. uc1:    call    diin    ;setup the CP/M FCB for given file
  680.     lxi    h,dire    ;setup input from disk reader
  681.     jmp    uc3
  682. uc2:    lxi    h,chin    ;input from the console
  683. uc3:    shld    re    ;REC compiler's I-O linkage
  684. uc4:    call    ucl    ;expose 'object program origin'
  685.     call    psiz    ;zero or two bytes
  686.     mov    a,c    ;check which
  687.     ora    b    ;
  688.     jnz    uc5    ;not zero may be two
  689.     lhld    c1    ;compile area pointer
  690.     xchg        ;
  691.     jmp    uc6    ;use compile pointer - no checks needed
  692. uc5:    dcx    b    ;verify two
  693.     dcx    b    ;
  694.     mov    a,c    ;
  695.     ora    b    ;
  696.     jnz    rer    ;reject anything else
  697.     call    deld    ;fetch origin into DE
  698.     lhld    c0    ;compile area lower limit
  699.     mov    a,e    ;does it lie in compile area?
  700.     sub    l    ;
  701.     mov    a,d    ;
  702.     sbb    h    ;
  703.     jc    uc6    ;no, it's below c0
  704.     lhld    c2    ;compile area upper limit
  705.     mov    a,l    ;
  706.     sub    e    ;
  707.     mov    a,h    ;
  708.     sbb    d    ;
  709.     jc    uc6    ;no, it's above c2
  710.     xchg        ;
  711.     shld    c1    ;readjust compile area pointer
  712.     xchg        ;
  713. uc6:    push    d    ;execution address
  714.     call    left    ;move up to source code
  715.     call    recrr    ;compile the source code
  716.     push    d    ;byte following compiled subroutine
  717.     call    putw    ;word from 8080 stack to PDL
  718.     call    putw    ;word from 8080 stack to PDL
  719.     ret        ;must be <call, ret>, not <jmp>
  720.  
  721. ;    (x)  Call a subroutine. <'XXXX'Hx> calls the subroutine at
  722. ;    the absolute location XXXX, which will be assumed to be a
  723. ;    REC predicate. If it is not, it will act as though it were
  724. ;    a FALSE predicate, so write ('XXXX'Hx;;) instead, or use (x).
  725.  
  726. go:    lhld    px    ;pointer to top argument
  727.     call    onel    ;move from PDL to 8080 stack
  728.     ret        ;must be <call, ret>, not <jmp>
  729.  
  730. ;    -------------------------------------------------------
  731. ;    Equivalences to subroutines in the REC nucleus.
  732. ;    -------------------------------------------------------
  733.  
  734.     ext    reclp,recrp,recco,recsc
  735.     ext    recop,recpr,reco1,recp1
  736.     ext    recdd,recms,recsq,recdq,reccm
  737.  
  738. ;    -------------------------------------------------------
  739. ;    Equivalences to subroutines outside this overlay.
  740. ;    -------------------------------------------------------
  741.  
  742.     ext    qu,nu,ns,hs
  743.     ext    eql,pe
  744.     ext    ga,gb,gbi,gwi
  745.     ext    sa,sai
  746.     ext    gxs,lcq,ind
  747.     ext    uco,he,hx
  748.     ext    blok,conc
  749.     ext    sum,dif,mpy,dvd
  750.     ext    decr,incr
  751.     ext    exch,comp
  752.     ext    lca,uca,lcb,ucb,ucd,lce,uce,lcf,ucf
  753.     ext    uci,lcj,ucj,lcl,lcm,ucm,ucn,lcn,ucp
  754.     ext    lcq,ucq,lcs,ucu,ucv,lcw,ucy,lcz,ucz
  755.     ext    qm,bra,ket,ip
  756.     ext    vble,libr
  757.     ext    lbr
  758.  
  759. ft:    dw    noop    ;blank
  760.     dw    noop
  761.     dw    recop    ; !    binary to hex string
  762.     dw    hx
  763.     dw    recdq    ; "    quoted expression
  764.     dw    qu
  765.     dw    recop    ; #    binary to decimal string
  766.     dw    ns
  767.     dw    recop    ; $    fetch a variable cell
  768.     dw    vble
  769.     dw    recop    ; %    restrict to one byte
  770.     dw    pe
  771.     dw    recop    ; &    exchange top numeric pair
  772.     dw    exch
  773.     dw    recsq    ; '    quoted expression
  774.     dw    qu
  775.     dw    reclp    ; (
  776.     dw    noop
  777.     dw    recrp    ; )
  778.     dw    noop
  779.     dw    recop    ; *    multiply
  780.     dw    mpy
  781.     dw    recop    ; +    add
  782.     dw    sum
  783.     dw    noop    ; ,    separator like space
  784.     dw    noop
  785.     dw    recms    ; -    subtract
  786.     dw    dif
  787.     dw    recop    ; .
  788.     dw    noop
  789.     dw    recop    ; /    divide [remainder, quotient]
  790.     dw    dvd
  791.     dw    recdd    ; 0    number    
  792.     dw    nu
  793.     dw    recdd    ; 1    number    
  794.     dw    nu
  795.     dw    recdd    ; 2    number    
  796.     dw    nu
  797.     dw    recdd    ; 3    number    
  798.     dw    nu
  799.     dw    recdd    ; 4    number    
  800.     dw    nu
  801.     dw    recdd    ; 5    number    
  802.     dw    nu
  803.     dw    recdd    ; 6    number    
  804.     dw    nu
  805.     dw    recdd    ; 7    number    
  806.     dw    nu
  807.     dw    recdd    ; 8    number    
  808.     dw    nu
  809.     dw    recdd    ; 9    number    
  810.     dw    nu
  811.     dw    recco    ; :
  812.     dw    noop
  813.     dw    recsc    ; ;
  814.     dw    noop
  815.     dw    recop    ; <    restrict workspace
  816.     dw    bra
  817.     dw    recpr    ; =    test equality of top pair
  818.     dw    eql
  819.     dw    recop    ; >    open workspace
  820.     dw    ket
  821.     dw    recpr    ; ?    test for error report
  822.     dw    qm
  823.     dw    recp1    ; @    execute subroutine
  824.     dw    ar
  825.     dw    recpr    ; A    advance pointer 1
  826.     dw    uca
  827.     dw    recpr    ; B    retract pointer 1
  828.     dw    ucb
  829.     dw    recop    ; C    compile
  830.     dw    ucc
  831.     dw    recop    ; D    delete text
  832.     dw    ucd
  833.     dw    recpr    ; E    equality between WS and PD
  834.     dw    uce
  835.     dw    recpr    ; F    find specified text
  836.     dw    ucf
  837.     dw    recop    ; G    fetch a block from memory
  838.     dw    ga
  839.     dw    recpr    ; H    ASCII hex to binary
  840.     dw    he
  841.     dw    recop    ; I    insert
  842.     dw    uci
  843.     dw    recop    ; J    jump to front
  844.     dw    ucj
  845.     dw    recop    ; K    call CP/M, keep DE, put value
  846.     dw    cpm
  847.     dw    recop    ; L    erase top of PDL
  848.     dw    ucl
  849.     dw    recpr    ; M    compare PDL and workspace
  850.     dw    ucm
  851.     dw    recpr    ; N    ;numerical comparison on PDL
  852.     dw    ucn
  853.     dw    recpr    ; O    decimal ASCII string to binary
  854.     dw    uco
  855.     dw    recop    ; P    put block into buffered memory
  856.     dw    ucp
  857.     dw    recop    ; Q    put workspace segment on PD
  858.     dw    ucq
  859.     dw    recop    ; R    read from keyboard
  860.     dw    ucr
  861.     dw    recop    ; S    store block in memory
  862.     dw    sa
  863.     dw    recop    ; T    write on screen
  864.     dw    uct
  865.     dw    recpr    ; U    search, yielding interval
  866.     dw    ucu
  867.     dw    recpr    ; V    U, including endpoints
  868.     dw    ucv
  869.     dw    recop    ; W    write on printer
  870.     dw    ucw
  871.     dw    recop    ; X    call library subroutine
  872.     dw    libr
  873.     dw    recpr    ; Y    recover previous position of p1
  874.     dw    ucy
  875.     dw    recop    ; Z    pointer 2 to end of text
  876.     dw    ucz
  877.     dw    reccm    ; [    comment
  878.     dw    noop
  879.     dw    recop    ; \    insert single byte in pair
  880.     dw    ip
  881.     dw    recop    ; ]
  882.     dw    noop
  883.     dw    recop    ; ^    increment top argument
  884.     dw    incr
  885.     dw    recop    ; _    exit to monitor
  886.     dw    boot
  887.     dw    recpr    ; `    true for waiting character
  888.     dw    chaw
  889.     dw    recpr    ; a    segment forward from p1
  890.     dw    lca
  891.     dw    recpr    ; b    segment backward from p2
  892.     dw    lcb
  893.     dw    recop    ; c    create block on PDL
  894.     dw    blok
  895.     dw    recpr    ; d     decrement but skip on zero
  896.     dw    decr
  897.     dw    recpr    ; e    extend workspace
  898.     dw    lce
  899.     dw    recpr    ; f    block fill
  900.     dw    lcf
  901.     dw    recop    ; g    non-incrementing byte fetch
  902.     dw    gb
  903.     dw    recop    ; h
  904.     dw    noop
  905.     dw    recop    ; i    input from designated port
  906.     dw    lci
  907.     dw    recop    ; j    null interval at p1
  908.     dw    lcj
  909.     dw    recop    ; k    call CP/M: no returned values
  910.     dw    cpml
  911.     dw    recop    ; l    put pz on PDL
  912.     dw    lcl
  913.     dw    recop    ; m    set aside top argument
  914.     dw    lcm
  915.     dw    recop    ; n    recover set-aside argument
  916.     dw    lcn
  917.     dw    recop    ; o    output from designated port
  918.     dw    lco
  919.     dw    recop    ; p    put px, py-px on PDL
  920.     dw    gxs
  921.     dw    recop    ; q    put p1, p2-p1 on PDL
  922.     dw    lcq
  923.     dw    recop    ; r    indirect replacement of address
  924.     dw    ind
  925.     dw    recop    ; s    store block in memory wrt limit
  926.     dw    lcs
  927.     dw    recop    ; t    type out indicated interval
  928.     dw    lct
  929.     dw    recop    ; u    incrementing byte fetch
  930.     dw    gbi
  931.     dw    recop    ; v    incrementing byte store
  932.     dw    sai
  933.     dw    recop    ; w    store workspace header
  934.     dw    lcw
  935.     dw    recpr    ; x    subroutine call  - no arguments
  936.     dw    go
  937.     dw    recop    ; y    fetch byte pair to PDL incr org
  938.     dw    gwi
  939.     dw    recop    ; z    null interval at p2
  940.     dw    lcz
  941.     dw    lbr    ; {    ;start a definition string
  942.     dw    noop
  943.     dw    recop    ; |    concatinate top two arguments
  944.     dw    conc
  945.     dw    noop    ; }    end of definition set
  946.     dw    noop
  947.     dw    recop    ; ~    complement or negate top arg
  948.     dw    comp
  949.     dw    recop    ; del
  950.     dw    noop
  951.  
  952. ;    -----------------------------------------------------
  953. ;    RAM memory which is required for the operation of REC
  954. ;    -----------------------------------------------------
  955.  
  956. ;    Relay area for input and output subroutines.
  957.  
  958. const:    db    (jmp)
  959. cnst:    dw    0000H
  960. conin:    db    (jmp)
  961. cnin:    dw    0000H
  962. conou:    db    (jmp)
  963. cnou:    dw    0000H
  964. read::    db    (jmp)    ;character input for REC compiler
  965. re::    dw    chin
  966. tyin::    db    (jmp)    ;single character input for R
  967. ti::    dw    chin
  968. tyou::    db    (jmp)    ;single character output for T
  969. to::    dw    chou
  970.  
  971. ;    Temporary storage used by the REC compiler.
  972.  
  973. xpd::    dw    0000    ;colon jump back to left parenthesis
  974. ypd::    dw    0000    ;false predicate jump chain
  975. zpd::    dw    0000    ;semicolon exit chain
  976.  
  977. ;    Pointers to the directories.
  978.  
  979. fxt::    dw    ft    ;pointer to fixed operator directory
  980. vrt::    dw    vt    ;pointer to subroutine directory
  981.  
  982. ;    Pointers to the area of compiled subroutines.
  983.  
  984. c0::    dw    0000H    ;beginning of compiling area
  985. c1::    dw    0000H    ;beginning of present compilation
  986. c2::    dw    0000H    ;final location of present compilation
  987.  
  988. ;    Pointers to REC/MARKOV pushdown list.
  989.  
  990. px::    dw    0000H    ;beginning of pushdown text
  991. py::    dw    0000H    ;end of pushdown text
  992. pz::    dw    0000H    ;end of available pushdown space
  993.  
  994. ;    Workspace pointers.
  995.  
  996. p0::    dw    0000H    ;beginning of workspace
  997. p1::    dw    0000H    ;beginning of marked segment
  998. p2::    dw    0000H    ;end of marked segment
  999. p3::    dw    0000H    ;end of text
  1000. p4::    dw    0000H    ;end of workspace
  1001.  
  1002. ;    I-O pointers.
  1003.  
  1004. rx::    dw    0000
  1005. ry::    dw    0000
  1006.  
  1007. ;    Linkage to input-output through ports.
  1008.  
  1009. qin::    db    (in)
  1010. qi::    db    00H
  1011.     ret
  1012.  
  1013. qou::    db    (out)
  1014. qo::    db    00H
  1015.     ret
  1016.  
  1017. ;    Temporary storage.
  1018.  
  1019. pt::    dw    0000
  1020.  
  1021. ;    Error flag.
  1022.  
  1023. er::    dw    0000
  1024.  
  1025. vt:    ds    100H        ;directory for programs compiled by REC
  1026.  
  1027. bmem:    ds    0        ;end of REC, begin free memory.
  1028.  
  1029.     end    main
  1030.  
  1031.