home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / sharew / exoten / rec / fxt87.asm < prev    next >
Encoding:
Assembly Source File  |  1980-01-01  |  40.4 KB  |  1,744 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 REC86.ASM, PDL86.ASM, MKV86.ASM, LIB86.ASM, and
  6. ;    FXT86.ASM. 
  7. ;
  8. ;    FXT86.ASM contains the following REC operators and
  9. ;    predicates:
  10. ;
  11. ;        C    compile a REC expression
  12. ;        i    input from designated port
  13. ;        k    call CP/M without residue
  14. ;        K    call CP/M, preserve FCB, return value
  15. ;        o    output from designated port
  16. ;        R    read one character from console
  17. ;        t    type message given header
  18. ;        T    type argument on PDL
  19. ;        W    write argument on LST:
  20. ;        X    noop: reserved for user extension
  21. ;        `    test if a character waits at keyboard
  22. ;
  23. ;    ------------------------------------------------------
  24. ;    REC version released during the 1984  Summer School of
  25. ;    the Microcomputer Applications Group of the I.C.U.A.P.
  26. ;    ------------------------------------------------------
  27. ;    8086 version with segments for code, PDL and WS.
  28. ;    ------------------------------------------------------
  29. ;
  30. ;            FXT87  -  Copyright (C) 1986
  31. ;            Gerardo Cisneros S.
  32. ;            Harold V. McIntosh
  33. ;            Derechos Reservados
  34. ;
  35. ;        [Harold V. McIntosh,  28 August 1980]
  36. ;        [Gerardo Cisneros, 8 February 1984]
  37. ;
  38. ;    Modification 1 - 1 January 1981.
  39. ;        a) Main program derives the values of const,
  40. ;          conin, conou from the address rst0 supposing
  41. ;          that BIOS starts out with the standard jump
  42. ;          vector.  Thus, REC need not be reassembled
  43. ;          to have fast access to I/O when CP/M varies.
  44. ;        b) T protected by pushes and pops of dx and bx.
  45. ;        c) Some changes made in memory allocation.
  46. ;    24 May 1981 - Zero flag to restrain L from too many pops
  47. ;    25 March 1982 - Y is now a predicate
  48. ;    29 May 1983 - ~ discontinued as argument exchange
  49. ;    29 May 1983 - ~ for unary negative or complement
  50. ;    29 May 1983 - N for numerical comparison on PDL
  51. ;    29 May 1983 - h discontinued, replaced by ''w
  52. ;    30 May 1983 - CPIR: jumps to BOOT rather than RER
  53. ;    8 July 1983 - C has object program origin as argument
  54. ;    8 July 1983 - C is an operator
  55. ;    8 July 1983 - C0 defined as lower bound of compile area
  56. ;    8 July 1983 - x moved from RECLIB
  57. ;    8 July 1983 - x is a predicate to call REC subroutines
  58. ;    9 July 1983 - Buffered CP/M input if no disk file given
  59. ;    14 July 1983 - W had its arguments reversed
  60. ;    14 January 1984 - <QIN ds 0>, <QOU ds 0> for sorcim.cnv
  61. ;    14 January 1984 - default extension .REC for 1st file
  62. ;    8 February 1984 - separate segments (GCS)
  63. ;    Apr 1984 - Disposable initialization code - GCS
  64. ;    9 May 1984 - Arguments of C reversed (GCS)
  65. ;    31 May 1984 - Error messages for Cp, PD and WS ovfl - GCS
  66. ;    11 June 1984 - DIIN/CPIN set up DMA address and seg. - GCS
  67. ;    18 June 1984 - Set DMA, then open; initialize VT - GCS
  68. ;    20 June 1984 - Rd ovf error on EOF and end of buffer - GCS
  69. ;    3 July 1984 - @@ takes over x, x is library predicate;
  70. ;    entry point for TL and combination table included. - GCS
  71. ;    14 Aug 1984 - Operator pair table extended - GCS
  72. ;    29 June 1985 - word-size entries in VT, x in. - GCS
  73. ;    6 July 1985 - 0<adr>C to give <org,siz> of Cpl. - GCS
  74. ;    8 Aug 1985 - Qm included in pair table - GCS
  75. ;    2 Feb 1986 - i fixed -GCS
  76. ;    11 Jul 1986 - V2 system calls, PATH search - GCS
  77. ;    10 Sept 1986 - R modified to read extended chars - GCS
  78. ;    9 Aug 1989 - Table of "..."x combinations added - GCS
  79. ;    6 Sep 1990 - Leave free memory data at ds:2-3&5-6 - GCS
  80. ;    11 Sep 1990 - Initial WS pointers p1 & p2 at p0 - GCS
  81. ;    =======================================================
  82.  
  83. bdos    equ    021H        ;MS-DOS software interrupt vector
  84.  
  85. DSIZ    equ    0020H        ;size of two parsed filenames
  86. FSIZ    equ    0010H        ;CP/M file name size
  87. TSIZ    equ    0080H        ;CP/M disk buffer size
  88.  
  89. ;    Linkage to input-output through ports.
  90.  
  91. QIN:
  92.     DB    0E4H        ;8-bit 8086 static IN instruction
  93. QI    db    00H
  94.     ret
  95.  
  96. QOU:
  97.     DB    0E6H        ;8-bit 8086 static OUT instruction
  98. QO    db    00H
  99.     ret
  100.  
  101. ;    =======================================================
  102. ;    Programs related to input-output and disk usage.
  103. ;    =======================================================
  104.  
  105. ;    bootstrap routine
  106.  
  107. boot:    mov    ax,04C00H
  108.     int    bdos
  109.  
  110. ;    Buffer read routine.
  111.  
  112. PTY:    push    bx        ;conserve (bx)
  113.     mov    es,RSEG        ;get segment address for buffer
  114.     mov    bx,RX        ;pointer to read buffer
  115.     cmp    bx,RY
  116.     jz    ptye
  117.     mov    al,es:[bx]        ;fetch byte
  118.     inc    bx        ;advance pointer to next byte
  119.     mov    RX,bx        ;update buffer pointer
  120.     pop    bx        ;restore (bx) - preserve all reg pairs
  121.     ret
  122. ptye:    mov    bx,'dR'        ;Report Rd ovfl and quit
  123.     jmp    FERR
  124.  
  125. ;    Console character read routine.  CP/M-86 compatible version
  126. ;    with direct access to CONIN.
  127.  
  128. chin:    push    cx
  129.     push    dx
  130.     mov    ah,7
  131.     int    bdos
  132.     test    al,al
  133.     jnz    chi
  134.     mov    ah,7
  135.     int    bdos
  136.     or    al,80H
  137. chi:    pop    dx
  138.     pop    cx
  139.     ret
  140.  
  141. ;    Buffered console character read routine, which is more
  142. ;    practical for use with CP/M.  Up to 126 characters may
  143. ;    be read using CP/M function 10, which is sufficient for
  144. ;    bootstrapping or generating test programs.  CHIN should
  145. ;    be used for longer input sequences, which must be error
  146. ;    free - incoming through a modem, for example.
  147.  
  148. buin:    push    bx
  149.     push    cx
  150.     push    dx
  151.     mov    bx,RX
  152.     cmp    bx,RY
  153.     jnz    BI5
  154. BI4:    mov    ah,9        ;(09) write message
  155.     mov    dx,(offset bume)
  156.     int    bdos
  157.     mov    ah,10        ;(0A) buffered read
  158.     mov    dx,(offset TBUF)
  159.     int    bdos
  160.     mov    ah,9        ;(09) write message
  161.     mov    dx,(offset crlf)
  162.     int    bdos
  163.     mov    bx,(offset TBUF)+2
  164.     mov    RX,bx
  165.     mov    al,-1[bx]
  166.     mov    ah,0
  167.     add    ax,bx
  168.     cmp    ax,bx
  169.     jz    BI4
  170.     mov    RY,ax
  171. BI5:    mov    al,[bx]
  172.     inc    bx
  173.     mov    RX,bx
  174.     pop    dx
  175.     pop    cx
  176.     pop    bx
  177.     ret
  178.  
  179. ;    Buffered read for repetitive compilation
  180.  
  181. bure:    mov    al,TSIZ-2
  182.     mov    TBUF,al
  183.     mov    ax,(offset buin)
  184.     mov    read,ax
  185.     mov    ax,(offset TBUF)
  186.     mov    RX,ax
  187.     mov    RY,ax
  188.     ret
  189.  
  190. ;    Console character out routine.  CP/M-86 compatible version
  191. ;    with direct access to CONOUT
  192.  
  193. chou:    push    cx
  194.     push    dx
  195.     mov    dl,al
  196.     mov    ah,6        ;(06) direct console IO
  197.     int    bdos
  198.     pop    cx
  199.     pop    dx
  200.     ret
  201.  
  202. ;    (`) Test for presence of waiting character (FALSE if
  203. ;    none waiting.  CP/M-86 compatible version with access
  204. ;    to CONST.
  205.  
  206. chaw:    push    cx
  207.     push    dx
  208. ;    mov    dl,-2
  209.     mov    ah,11        ;(11) Check keyboard status
  210.     int    bdos
  211.     pop    dx
  212.     pop    cx
  213.     test    al,al
  214.     jnz    chw
  215.     ret
  216. chw:    jmp    SKP
  217.  
  218. ;    Printer output routine.
  219.  
  220. PROU:    push    bx
  221.     push    dx
  222.     push    cx
  223.     mov    ah,5        ;(05) output through LST:
  224.     mov    dl,al
  225.     int    bdos
  226.     pop    cx
  227.     pop    dx
  228.     pop    bx
  229.     ret
  230.  
  231. ;    (R) REC read operator.
  232.  
  233. UCR:    mov    cx,1        ;one byte to be inserted
  234.     call    NARG        ;close last arg, verify space
  235.     push    bx
  236.     call    word ptr tyin    ;get byte from console input
  237.     pop    bx
  238.     mov    [bx],al        ;store on PDL
  239.     inc    bx        ;advance pointer
  240.     mov    PY,bx        ;record end of argument
  241.     ret
  242.  
  243. ;    (t) Write indirect operator.  <org,siz,t> prints the
  244. ;    indicated message, leaves no residue.
  245.  
  246. LCT:    mov    bx,PX        ;fetch argument pointer
  247.     call    ONEL        ;move one argument to 8086 stack
  248.     call    CXLD        ;get org and segment
  249.     mov    bx,cx        ;org to bx
  250.     pop    dx        ;size to dx
  251.     add    dx,bx        ;org+size=end
  252.     jmp    UT1        ;use write cycle in UCT
  253.  
  254. ;    (TL)  Often-used combination for which a single call
  255. ;    is compiled.
  256.  
  257. UCTL:    call    UCT        ;type argument and
  258.     jmp    UCL        ;lift it
  259.  
  260. ;    (T) REC write operator. <'XXX' T> will write XXX on
  261. ;    the console, leaving it on the PDL.
  262.  
  263. uct:    mov    dx,PY        ;fetch terminal address
  264.     mov    bx,PX        ;beginning address to (bx)
  265.     mov    ax,ds
  266.     mov    es,ax
  267. ut1:    cmp    dx,bx
  268.     jz    ut2        ;they match, we're done
  269.     mov    al,es:[bx]    ;get byte out of memory
  270.     push    bx
  271.     push    dx
  272.     push    es
  273.     call    word ptr tyou    ;tyou is in the data segment
  274.     pop    es
  275.     pop    dx        ;recover the saved registers
  276.     pop    bx
  277.     inc    bx        ;advance pointer
  278.     jmp    UT1        ;repeat
  279. ut2:    ret
  280.  
  281. ;    (W)  REC print operator.  <org, siz, W> will print the
  282. ;    indicated text on the list device, and then erase its
  283. ;    arguments.
  284.  
  285. UCW:    mov    bx,PX        ;pointer to arguments
  286.     call    ONEL        ;size from PDL to 8086 stack
  287.     call    CXLD        ;org and segment addr to cx and es
  288.     mov    bx,cx        ;place text origin in (bx)
  289.     pop    dx        ;place length in (dx)
  290. UWW:    test    dx,dx        ;check for zero length
  291.     jz    UWX        ;no more to print
  292.     mov    al,es:[bx]    ;fetch a byte
  293.     push    bx        ;we need to be sure that dx and bx are
  294.     push    dx        ;preserved whatever the print routine
  295.     push    es
  296.     call    PROU        ;send it to printer
  297.     pop    es
  298.     pop    dx        ;recover bx
  299.     pop    bx        ;and dx
  300.     dec    dx        ;diminish count
  301.     inc    bx        ;advance pointer
  302.     jmp    UWW        ;repeat
  303. UWX:    ret
  304.  
  305. ;    (i)  Input from designated port.  <port, i> leaves
  306. ;    <port, byte> so that after disposing of <byte>, <port>
  307. ;    can be reused.
  308.  
  309. LCI:    mov    bx,PX        ;get pointer to top argument on PDL
  310.     mov    al,[bx]        ;only the low order byte matters
  311.     mov    cs:QI,al        ;place it in teme IN instruction
  312.     mov    cx,1        ;we're only going to read one byte
  313.     call    NARG        ;prepare a place for it on the PDL
  314.     call    QIN        ;execute the captive IN instruction
  315.     mov    [bx],al        ;storing the incoming byte on the PDL
  316.     inc    bx        ;always ready for the next byte
  317.     mov    PY,bx        ;close off the argument
  318.     ret            ;and we're through
  319.  
  320. ;    (o) Output from designated port  -  <port, byte, o>
  321. ;    leaves <port>, facilitating multiple OUTs through the
  322. ;    same port.
  323.  
  324. LCO:    mov    bx,PX        ;pointer to last argument - output byte
  325.     mov    CH,[bx]        ;tuck it into register b
  326.     call    UCL        ;erase the top argument
  327.     mov    al,[bx]        ;(bx) points to next argument - get it
  328.     mov    cs:QO,al        ;store in tame OUT instruction
  329.     mov    al,CH        ;output must be from accumulator
  330.     jmp    QOU        ;execute the prepared OUT instruction
  331.  
  332. ;    =======================================================
  333. ;
  334. ;    Communication with MS-DOS takes two forms:  <args, n, K>
  335. ;    which leaves <arg, code> on the pushdown list, or else
  336. ;    <args, n, k> which leaves nothing on the pushdown list.
  337. ;    In either case "args" is one or two arguments, depending
  338. ;    on the function call and "n" is the MS-DOS function
  339. ;    number.  Each argument contains values for one or two
  340. ;    registers; up to four registers may be assigned values.
  341. ;    Since some functions require an argument in AL, this is
  342. ;    taken from the HIGH order byte of "n".  For most 
  343. ;    functions the value returned ("code") is the value of
  344. ;    AX.  Functions which will take two arguments from the
  345. ;    PDL are 27H, 29H, 3CH, 3EH and all others above 3EH.
  346. ;    Functions beyond 3EH not actually requiring the second
  347. ;    argument will nevertheless lift an extra argument;
  348. ;    loading an extra 0 will do.  If a two byte argument XX
  349. ;    is given where two registers R1:R2 are expected (R1
  350. ;    being the high order word), R1 will be assigned the
  351. ;    value of DS and XX will be loaded into R2. With the
  352. ;    exception of functions 2BH and 2DH, where arg1 is
  353. ;    read as CX:DX, if arg1 is WW:XX and arg2 is YY:ZZ,
  354. ;    XX will be loaded into DX and SI, ZZ will be loaded
  355. ;    into BX and DI, YY (or DS if YY is absent) will be
  356. ;    loaded into ES, and WW will be loaded into DS (unless
  357. ;    WW is absent, in which case DS does not change)
  358. ;    In the list below "fcb" and "buffer" represent the
  359. ;    addresses of a file control block and a buffer,
  360. ;    respectively. Some functions return additional values
  361. ;    besides AX. These are indicated in the list; each PDL
  362. ;    argument produced by K is separated by a slash. Addr4
  363. ;    means a 4 byte address (seg:offset). An asterisk 
  364. ;    indicates that an extra value -1 (on error, in which
  365. ;    case the remaining AX value is the error code) or
  366. ;    an extra copy of AX (if no error) is returned.
  367. ;
  368. ;    The functions are:
  369. ;
  370. ;    num    function        "arg1"    "arg2"    "code"
  371. ;    ---    --------        -----    ------    ------
  372. ;
  373. ;    0    program terminate    0    -    -
  374. ;    1    kbd input        0    -    char
  375. ;    2    video output        char    -    AX
  376. ;    3    aux input        0    -    char
  377. ;    4    aux output        char    -    AX
  378. ;    5    printer output        char    -    AX
  379. ;    6    direct cons I/O        DX    -    AX
  380. ;    7    dir cons input, no echo    0    -    AX
  381. ;    8    cons input, no echo    0    -    AX
  382. ;    9    print string        buffer    -    AX
  383. ;    10    buffered kbd input    buffer    -    AX
  384. ;    11    keyboard status        0    -    stat
  385. ;    12    char inp w/buffer flush    DX    -    AX
  386. ;    13    disk reset        0    -    AX
  387. ;    14    select disk        disk    -    AX
  388. ;    15    open file        fcb    -    code
  389. ;    16    close file        fcb    -    code
  390. ;    17    search once        fcb    -    code
  391. ;    18    search again        fcb    -    code
  392. ;    19    delete file        fcb    -    code
  393. ;    20    sequential read        fcb    -    code
  394. ;    21    write 1 record        fcb    -    code
  395. ;    22    create file        fcb    -    code
  396. ;    23    rename file        fcb    -    code
  397. ;    25    current disk        0    -    disk
  398. ;    26    set DMA address        dma    -    AX
  399. ;    27    alloc tbl addr        not implemented
  400. ;    33    random read        fcb    -    code
  401. ;    34    random write        fcb    -    code
  402. ;    35    file size        fcb    -    code
  403. ;    36    set random rec field    fcb    -    AX
  404. ;    37    set vector        addr    -    AX
  405. ;    38    create new pgm seg    seg    -    AX
  406. ;    39    random block read    fcb    CX    AX
  407. ;    40    random block write    fcb    CX    AX
  408. ;    41    parse file name        DS:SI    ES:DI    AX
  409. ;    42    get date        0    -    CX:DX/AX
  410. ;    43    set date        CX:DX    -    AX
  411. ;    44    get time        0    -    CX:DX/AX
  412. ;    45    set time        CX:DX    -    AX
  413. ;    46    set/reset verify flag    0    -    AX
  414. ;    47    get DMA address        0    -    addr4/AX
  415. ;    48    get DOS version No.    0    -    AX
  416. ;    49    term and stay res.    DX    -    -
  417. ;    51    ctrl-break check    DX    -    DX
  418. ;    53    get vector        0    -    addr4
  419. ;    54    get disk free space    disk    -  ax:cx/dx:bx/code
  420. ;    56    ret country dep info    addr    -    AX/*
  421. ;    57    create subdir        addr    -    AX/*
  422. ;    58    remove dir entry    addr    -    AX/*
  423. ;    59    change curr dir        addr    -    AX/*
  424. ;    60    create a file        addr    attrib    AX/*
  425. ;    61    open a file        addr    -    AX/*
  426. ;    62    close a file        0    handle    AX/*
  427. ;    63    read file/dev        buffer    No:Hdl    AX/*
  428. ;    64    write file/dev        buffer    No:Hdl    AX/*
  429. ;    65    delete file        addr    0    AX/*
  430. ;    66    move file pointer    DX    CX:Hdl    dx:ax/ax/*
  431. ;    67    change file mode    addr    0    CX/AX/*
  432. ;    68    IOCTL            0    handle    dx/ax/*
  433. ;    69    duplicate a handle    0    handle    AX/*
  434. ;    70    force dupl of handle    0    CX:BX    AX/*
  435. ;    71    get curr dir        disk    buffer    AX/*
  436. ;    72    allocate memory        0    BX    AX/*
  437. ;    73    free allocated mem    0    ES:0    AX/*
  438. ;    74    mod alloc mem blocks    0    ES:BX    BX/AX/*
  439. ;    75    load or exec a pgm    DS:DX    ES:BX    AX/*
  440. ;    76    terminate a process    0    0    -
  441. ;    77    get ret code        0    0    AX/*
  442. ;    78    find first        addr    attrib    AX/*
  443. ;    79    find next        0    0    AX/*
  444. ;    84    get verify state    0    0    AX/*
  445. ;    86    rename a file        DS:DX    ES:DI    AX/*
  446. ;    87    get/set file date/time    DX    CX:BX    AX/*
  447. ;
  448. ;    =======================================================
  449.  
  450. ;    (K)  Set up communication with MS-DOS.
  451.  
  452. CPM:    call    CPM0        ;use code in common with k
  453.     lahf            ;save flags for #42H and #45H
  454.     cmp    al,2AH        ;was it get date?
  455.     jnc    cpm5
  456. cpm4b:    mov    ax,bp        ;extend al sign if below
  457.     cbw
  458.     push    ax
  459. cpm4a:    call    PUTW        ;to PDL (jmp PUTW won't do)
  460.     ret
  461.  
  462. cpm5:    jz    cpm6        ;treat #2A and #2C the same
  463.     cmp    al,2CH        ;get time?
  464.     jnz    cpm8
  465. cpm6:    push    bp        ;AX returned by bdos
  466.     push    cx
  467.     push    dx
  468. cpm7:    call    PUTW        ;two words go to the PDL
  469.     call    PUTW
  470.     call    CONC        ;concatenate them
  471.     jmp short cpm4a        ;then put AX on the PDL
  472.  
  473. cpm8:    cmp    al,2FH        ;get DMA?
  474.     jz    cpm9        ;treat the same as #35H
  475.     cmp    al,35H        ;get vector?
  476.     jnz    cpm10
  477. cpm9:    push    es        ;return ES:BX
  478.     push    bx
  479.     call    PUTW        ;two words go to the PDL
  480.     call    PUTW
  481.     jmp    CONC        ;concatenate them
  482.  
  483. cpm10:    cmp    al,33H        ;ctrl-break check/set?
  484.     jnz    cpm11
  485.     push    dx        ;yes, return DX
  486.     jmp short cpm4a
  487.  
  488. cpm11:    cmp    al,42H        ;LSEEK?
  489.     jnz    cpm12c
  490.     sahf            ;yes, get returned carry bit
  491.     mov    ax,bp
  492.     jnc    cpm11a
  493.     mov    bp,0FFFFH    ;carry on, ret -1 code
  494. cpm11a:    push    bp        ;else original ax
  495.     push    ax        ;ax or error code
  496.     push    dx
  497.     jmp short cpm7        ;conc ax and dx
  498.  
  499. cpm12c:    cmp    al,36H        ;get disk free space?
  500.     ja    cpm14
  501.     jnz    cpm13
  502.     push    bp        ;ax/error code (-1) on top
  503.     push    dx        ;ret DX:BX next
  504.     push    bx
  505.     push    bp        ;and CX:AX below
  506.     push    cx
  507.     call    PUTW        ;two words go to the PDL
  508.     call    PUTW
  509.     call    CONC        ;concatenate them
  510.     jmp short cpm7
  511.  
  512. cpm13:    cmp    al,30H        ;get version No.?
  513.     jnz    cpm4b        ;sign extend if not
  514. cpm13a:    push    bp
  515.     jmp short cpm4a
  516.  
  517. cpm14:    push    ax
  518.     cmp    al,43H        ;CHMOD?
  519.     jnz    cpm15
  520.     push    cx
  521. cpm14a:    call    PUTW
  522. cpm12:    pop    ax
  523.     sahf
  524.     mov    ax,bp
  525.     jnc    cpm12a
  526.     mov    bp,0FFFFH    ;unsuccessful, ind by -1
  527. cpm12a:    push    bp
  528.     push    ax
  529. cpm12b:    call    PUTW        ;handle/err code to PDL
  530.     jmp short cpm4a        ;"carry" ind to PDL
  531.  
  532. cpm15:    cmp    al,44H        ;IOCTL?
  533.     jnz    cpm16
  534.     push    dx
  535.     jmp short cpm14a
  536.  
  537. cpm16:    cmp    al,4AH        ;SETBLOCK?
  538.     jnz    cpm12
  539.     push    bx
  540.     jmp short cpm14a
  541.  
  542. ;    Common code for K and k.
  543.  
  544. CPM0:    mov    bx,PX        ;pointer to function number
  545.     call    ONEL        ;transfer to stack
  546.     mov    bp,sp        ;access it through bp
  547.     mov    al,[bp]        ;this is the function number
  548.     cmp    al,27H        ;random block read?
  549.     jz    cpm0a        ;yes, 2 more args
  550.     cmp    al,29H        ;parse file name?
  551.     jz    cpm0a        ;yes, 2 more args
  552.     cmp    al,3CH        ;create?
  553.     jz    cpm0a        ;yes, 2 more args
  554.     cmp    al,3EH        ;close?
  555.     jb    cpm1        ;everything else below uses 1 arg
  556. cpm0a:    call    CXLD        ;top arg to ES:CX, lift from PDL
  557. cpm1:    push    cx        ;keep while loading lower
  558.     push    es
  559.     call    ESLD        ;DS or high word to ES
  560.     mov    dx,[bx]        ;low word of arg to DX
  561.     mov    cx,es        ;save high word in CX
  562.     pop    es        ;retrieve 2nd arg (if any)
  563.     pop    di
  564.     mov    al,1[bp]    ;function number (inverted) into ax
  565.     mov    ah,[bp]
  566.     push    ds        ;save ds before modifying
  567.     mov    ds,cx        ;high word of 1st arg ends up in ds
  568.     mov    cx,es        ;high word of 2nd will be in cx and es
  569.     mov    bx,di        ;low word of 2nd goes to di and bx
  570.     mov    si,dx        ;low word of 1st goes to dx and si
  571.     cmp    ah,2BH        ;set date?
  572.     jz    cpm2        ;yes, set CX from high(1st)
  573.     cmp    ah,2DH        ;set time?
  574.     jnz    cpm3
  575. cpm2:    mov    cx,ds        ;set CX from high(1st)
  576. cpm3:    cmp    ah,47H        ;get current dir?
  577.     jnz    cpm4
  578.     mov    ds,cx        ;yes: set ds:si from 2nd arg
  579.     mov    si,bx
  580. cpm4:    int    bdos        ;DO IT!
  581.     pop    ds        ;restore our data seg base
  582.     pop    bp        ;retrieve original function No. to al
  583.     xchg    bp,ax        ;save returned ax in bp
  584.     ret
  585.  
  586. ;    (k)  Call to CP/M without any value returned.
  587.  
  588. CPML:    call    CPM0        ;use common code
  589.     jmp    UCL        ;get rid of lowest argument
  590.  
  591. ;    -------------------------------------------------------
  592. ;    Disk input-output routine working through CP/M.
  593. ;    -------------------------------------------------------
  594.  
  595. ;    Set up a to read a source file whose name is given on the
  596. ;    PDL.  A default extension .REC is appended if not present;
  597. ;    an error exit is taken if the file cannot be opened.
  598. ;    The file handle is stored at FLDES if the open is
  599. ;    successful.
  600.  
  601. DIIN:    mov    bx,PX        ;point at drive designator
  602.     mov    al,[bx]
  603.     cmp    al,'@'        ;is it default?
  604.     jne    di1
  605.     call    UCL        ;yes, get rid of it
  606.     jmp short CPIN
  607. di1:    inc    bx        ;no, append a colon
  608.     mov    byte ptr [bx],':'
  609.     inc    bx
  610.     mov    PY,bx
  611.     call    EXCH        ;attach it to the filename
  612.     call    CONC
  613.  
  614. CPIN:    call    GXS        ;find out about the extension
  615.     call    LCW
  616.     call    NU
  617.     db    2
  618.     dw    4
  619.     call    LCB
  620.     jmp short rcxt        ;not 4 chars, add .REC
  621.     nop            ;beware of true skip
  622.     call    QU
  623.     dw    4
  624.     db    '.REC'
  625.     call    UCE        ;check last 4 chars
  626.     jmp short rcxt
  627.     nop            ;beware of true skip
  628.     call    LCW        ;restore workspace
  629.     jmp short cp1        ;.REC found
  630.  
  631. rcxt:    call    LCW        ;restore WS
  632.     call    QU        ;append extension
  633.     dw    4
  634.     db    '.REC'
  635.     call    CONC
  636. cp1:    call    NU        ;terminate with NUL
  637.     db    2
  638.     dw    0
  639.     call    CONC
  640.     mov    dx,PX        ;start of string
  641.     mov    ax,3D00H    ;sys call: open for reading
  642.     int    bdos
  643.     jc    cp2
  644.     mov    FLDES,ax    ;else we have a handle
  645.     mov    dx,(offset TBUF)
  646.     mov    RX,dx        ;set buffer pointers
  647.     mov    RY,dx
  648.     mov    RSEG,ds
  649. cp2:    ret            ;immediate return if carry set
  650.  
  651. ;    Read from disk buffer, replenish buffer when empty.
  652.  
  653. DIRE:    push    bx
  654.     mov    bx,RX        ;pointer to current byte
  655.     cmp    bx,RY        ;skip if equal
  656.     jnz    DI5        ;still have bytes in the buffer?
  657.     push    dx        ;
  658.     push    cx        ;
  659.     mov    bx,FLDES    ;no, get file handle
  660.     mov    dx,(offset TBUF)
  661.     mov    cx,080H        ;128-byte sectors
  662.     mov    ah,03FH        ;sys call: read
  663.     int    bdos
  664.     jc    dier
  665.     test    ax,ax
  666.     jz    dier        ;ax=0 means no more bytes
  667.     mov    bx,(offset TBUF) ;start of buffer
  668.     mov    RX,bx        ;store it in rx
  669.     add    ax,bx        ;end of buffer
  670.     mov    RY,ax        ;store it in ry
  671.     pop    cx
  672.     pop    dx
  673.     mov    ah,0
  674. DI5:    mov    al,[bx]        ;common continuation
  675.     inc    bx        ;byte in acc, advance pointer
  676.     mov    RX,bx        ;store position of next byte
  677.     pop    bx
  678.     ret
  679. dier:    mov    bx,'dR'
  680.     jmp    FERR
  681.  
  682. ;    (C) REC compiling operator which takes the designation
  683. ;    of the compiling source from the PDL. The alternatives
  684. ;    are:
  685. ;
  686. ;    ''<dest>C        input program from console
  687. ;    'file' 'D'<dest> C    take<file.rec> from disk D
  688. ;    p<dest>C        pushdown list
  689. ;    q<dest>C        workspace
  690. ;    <org,siz,dest,C>    memory from address org onward
  691. ;
  692. ;    where <dest> designates the destination area for the
  693. ;    compilation: C1 if null, the address given otherwise.
  694. ;    In general, if the top argument is of length zero, the
  695. ;    console is the source, if it is of length one the named
  696. ;    disk is the source [@=current disk, A, B, ... up to the
  697. ;    system's limit], and if the argument has length 2, the
  698. ;    combination of <org, siz> from the memory applies.  It
  699. ;    is the programmer's responsibility to avoid nonexistent
  700. ;    memory, disk units, and the like.
  701.  
  702. UCC:    push    c1
  703.     mov    cx,PY
  704.     sub    cx,PX
  705.     jnz    UC5
  706.     mov    dx,C1        ;use compile pointer
  707.     jmp    short UC6
  708. UC5:    call    ESLD        ;get segment, ignore
  709.     mov    dx,[bx]        ;get address to use
  710. UC6:    mov    C1,dx        ;record as C1
  711.     call    UCL        ;remove <dest> argument
  712.     mov    ax,PY        ;check length of <source> argument
  713.     sub    ax,PX
  714.     jz    UC2        ;zero means console
  715.     cmp    ax,1        ;test for one byte
  716.     jz    UC1        ;one means disk designation
  717.     cmp    ax,2        ;verify that we've got two bytes
  718.     jnz    UC7        ;no provision for other than 1, 2 bytes
  719.     mov    bx,(offset PTY)        ;setup readin from pseudoteletype
  720.     mov    read,bx        ;
  721.     call    CXLD        ;load two numerical arguments
  722.     jcxz    UC8        ;zero means return cpl. area ptrs.
  723.     mov    dx,[bx]        ;bx contains PX for second argument
  724.     call    ESLD        ;load segment address of buffer
  725.     mov    RX,dx        ;origin of REC source code
  726.     add    dx,cx        ;length of source code
  727.     mov    RY,dx        ;end of source code
  728.     mov    RSEG,es        ;segment of source code
  729.     jmp    short UC4    ;compile once rx, ry set up
  730. UC8:    mov    bx,C2        ;compute size
  731.     sub    bx,C1
  732.     push    bx        ;size on stack
  733.     push    cs
  734.     push    C1        ;origin on stack
  735.     call    PUTW
  736.     call    PUTW
  737.     call    CONC        ;make 4-byte address cs:C1
  738.     jmp    short UC9    ;then to the PDL
  739. UC1:    call    DIIN        ;setup the CP/M FCB for given file
  740.     jc    OPFL        ;carry says open failed
  741.     pop    dx        ;recover c1
  742.     mov    bx,(offset DICL)
  743.     push    bx        ;set return through DICL (close)
  744.     push    dx        ;c1 back on the stack
  745.     mov    bx,(offset DIRE)    ;setup input from disk reader
  746.     jmp    UC3        ;compile once input source set up
  747. UC2:    mov    bx,(offset CHIN)    ;input from the console
  748. UC3:    mov    read,bx        ;
  749. UC4:    call    EMCE
  750.     push    dx
  751.     call    PUTW
  752. UC9:    call    PUTW
  753.     pop    c1
  754.     ret
  755. UC7:    pop    c1
  756.     call    RER
  757.  
  758. OPFL:    call    UCTL        ;type filename
  759.     mov    dx,(offset nfil)
  760.     jmp    FERM        ;type error message and quit
  761.  
  762. ;    (X)  noop in this version
  763.  
  764. LIBO:    ret
  765.  
  766. ;    Close the file after compiling
  767.  
  768. DICL:    mov    bx,FLDES    ;get the handle
  769.     mov    ah,3EH        ;sys call: close
  770.     int    bdos
  771.     ret
  772.  
  773. ;    Single-shot compilation from a disk file
  774.  
  775. SSHOT:    call    EMCX        ;compile the program file
  776.     call    DICL        ;close it
  777.     mov    cx,DSIZ
  778.     mov    di,(offset TFCB)
  779.     mov    si,P3
  780.     mov    ax,ds
  781.     mov    ds,WSEG
  782.     mov    es,ax
  783.     repnz    movsb        ;retrieve parsed filenames
  784.     mov    si,es:P1
  785.     mov    bx,si
  786.     mov    cl,[si]
  787.     inc    cx
  788.     mov    di,(offset TBUF)
  789.     repnz    movsb        ;retrieve command line
  790.     mov    ds,ax        ;restore data segment base value
  791.     inc    bx
  792.     mov    P2,bx
  793.     call    UCD        ;delete character count from workspace
  794.     call    EMCU        ;execute the program file
  795.     jmp    short bootie    ;return to CP/M if false
  796.     nop            ;beware jump span
  797. bootie: jmp    boot
  798.  
  799. ;    Multiple compilations from the console
  800.  
  801.  
  802. nodi:    call    bure    ;no disk file: compile interactively
  803.     call    INRE
  804.     call    EMCX
  805.     call    EMCU
  806.     jmp    short nodi
  807.     nop
  808.     jmp    nodi
  809.  
  810. ;    Type error message and quit
  811.  
  812. FERR:    mov    EMSG,bx
  813.     mov    dx,(offset EMSGS)
  814. FERM:    mov    ah,9
  815.     int    bdos
  816.     jmp    boot
  817.  
  818. ;    Undefined subroutine exit
  819.  
  820. USUB:    shr    al,1        ;restore character
  821.     cmp    al,' '
  822.     jb    usu1
  823.     cmp    al,'~'
  824.     ja    usu1        ;leave BEL for control chars
  825.     mov    usby,al        ;others get typed
  826. usu1:    mov    dx,(offset usms)
  827.     jmp short FERM
  828.  
  829. ;    END OF PERMANENT CODE.  THE INSTRUCTIONS FOLLOWING THIS
  830. ;    WILL BE OVERWRITTEN AS SOON AS THE FIRST REC PROGRAM
  831. ;    IS COMPILED.
  832.  
  833. ENDREC:
  834.  
  835. ;    ================
  836. ;    = main program =
  837. ;    ================
  838.  
  839.  
  840. MAIN:
  841. ;    finit
  842.     db    9BH,0DBH,0E3H
  843.     mov    ax,dgroup
  844.     mov    es,ax
  845.     mov    cx,080H
  846.     mov    si,0
  847.     mov    di,si
  848.     cld
  849.     repnz    movsw        ;transfer PSP to data segment
  850.     mov    ax,es
  851.     mov    ds,ax
  852.     mov    di,(offset VT)    ;set up to initialize vars/subs
  853.     mov    cx,021H        ;the number of variables
  854.     mov    ax,0000
  855.     repnz    stosw        ;set variables to zero
  856.     mov    cx,05EH        ;number of subroutine entries
  857.     mov    ax,(offset usub)    ;undef subroutine exit
  858.     repnz    stosw
  859.     mov    word ptr [di],0000    ;clear entry for DEL
  860.     mov    bx,02
  861.     mov    dx,cs
  862.     sub    [bx],dx
  863.     mov    ax,[bx]        ;get total No. of paragraphs-c.s.base
  864.     shr    ax,1        ;half of leftover
  865.     mov    dx,01000H    ;tentative size for compile area
  866.     cmp    ax,dx
  867.     jnb    vtc1
  868.     mov    dx,ax        ;less than 128k, use half
  869. vtc1:    sub    [bx],dx        ;subtract c.s.paragraphs
  870.     mov    ax,cs
  871.     add    ax,dx
  872.     mov    es,ax        ;new data segment base
  873.     mov    di,offset dlst
  874.     mov    si,di
  875.     mov    cx,di
  876.     inc    cx
  877.     std
  878.     repnz    movsb        ;move data to new segment
  879.     mov    ax,es
  880.     mov    ds,ax
  881.     mov    cl,4
  882.     shl    dx,cl
  883.     dec    dx        ;sacrifice a byte to avoid C2=0
  884.     mov    C2,dx
  885.     mov    ax,[bx]        ;get leftover
  886.     shr    ax,1
  887.     mov    dx,01000H
  888.     cmp    ax,dx
  889.     jnb    vtc2
  890.     mov    dx,ax
  891. vtc2:    sub    [bx],dx        ;subtract d.s.paragraphs
  892.     mov    ax,ds
  893.     add    ax,dx
  894.     mov    es,ax
  895.     mov    WSEG,ax
  896.     shl    dx,cl        ;first address beyond data segment
  897.     dec    dx
  898.     dec    dx
  899.     xchg    dx,bx
  900.     mov    word ptr [bx],0FFFFH    ;end-of-PDL marker
  901.     mov    PZ,bx
  902.     xchg    dx,bx
  903.     mov    ax,[bx]        ;leftover once more
  904.     shr    ax,1
  905.     mov    dx,01000H
  906.     cmp    ax,dx
  907.     jnb    vtc3
  908.     mov    dx,ax
  909. vtc3:    sub    [bx],dx
  910.     mov    ax,es
  911.     add    ax,dx
  912.     shl    dx,cl
  913.     dec    dx
  914.     dec    dx
  915.     xchg    dx,bx
  916.     mov    es:word ptr [bx],0    ;mark end of ws
  917.     mov    P4,bx
  918.     xchg    dx,bx
  919.     mov    es,ax
  920.     mov    ax,[bx]        ;leftover is for stack
  921.     mov    dx,01000H
  922.     cmp    ax,dx
  923.     jb    vtc4
  924.     mov    ax,dx
  925. vtc4:    sub    [bx],dx        ;final number of free paragraphs
  926.     shl    ax,cl
  927.     cli
  928.     mov    sp,ax
  929.     mov    ax,es
  930.     mov    ss,ax
  931.     sti
  932.     add    ax,dx        ;address of next free paragraph
  933.     mov    [bx+4],ax    ;to be saved at offset 6 of PSP
  934.     mov    dx,offset boot
  935.     push    dx
  936.     cld
  937.     mov    si,(offset TBUF)    ;pointer to command buffer
  938.     mov    cl,[si]    ;get count
  939.     mov    ch,0
  940.     jcxz    mj1        ;tail empty?
  941.     inc    si        ;no, get rid of leading blanks
  942. mj0:    lodsb
  943.     cmp    al,' '
  944.     jnz    majn
  945.     loop    mj0
  946. mj1:    call    STATS        ;tail empty: type memory usage stats
  947.     jmp    nodi        ;and go to TTY: loop
  948.  
  949. majn:    dec    si        ;command line tail to WS
  950.     mov    di,P1    ;next byte of WS
  951.     mov    es,WSEG    ;load ES with WS base
  952. mb0:    lodsb
  953.     cmp    al,'a'    ;fold lower into upper case
  954.     jb    mb1
  955.     cmp    al,'z'
  956.     ja    mb1
  957.     sub    al,32
  958. mb1:    stosb
  959.     loop    mb0
  960.     mov    P3,di
  961.     mov    P2,di    ;delimit the tail
  962.     call    QU    ;find a blank
  963.     dw    1
  964.     db    ' '
  965.     call    UCF
  966.     jmp short mb2
  967.     nop        ;beware of true skip
  968.     call    UCD    ;get rid of the blank
  969.     call    UCJ    ;span the name
  970. mb2:    call    QUEM    ;first argument to PDL complement
  971.     call    UCD    ;delete from WS
  972.     call    UCZ    ;span WS
  973.     call    LCQ
  974.     call    PE    ;set up new tail length
  975.     call    LCJ
  976.     call    UCI    ;insert at start of WS
  977.     call    UCL    ;lift p1 from PDL
  978.     call    UCZ
  979.     call    MVENV    ;move environment string to WS
  980.     call    QU
  981.     dw    5
  982.     db    'PATH='    ;look for PATH string
  983.     call    UCF
  984.     jmp short mb8    ;skip if not found
  985.     nop        ;beware of true skip
  986.     call    QU    ;else delimit up to NUL
  987.     dw    1
  988.     db    0
  989.     call    UCU
  990.     nop
  991.     nop        ;PATH found, U must be true
  992.     nop
  993.     call    BRA    ;restrict to PATHs
  994.     call    LCJ    ;null at start of WS
  995.     call    UCQ    ;start with a null pathname
  996.     jmp short mb5
  997.  
  998. mb4:    call    UCL    ;lift failed filename
  999.     call    QU    ;look for next path
  1000.     dw    1
  1001.     db    ';'
  1002.     call    UCU
  1003.     jmp short mb7    ;skip if last
  1004.     nop
  1005.     call    UCQ    ;otherwise copy it
  1006.     call    LCZ
  1007.     call    UCA    ;advance over semicolon
  1008.     nop
  1009.     nop
  1010.     nop        ;filler for false exit
  1011. mb5:    call    SLOP    ;append \ if needed, try to open
  1012.     jc    mb4    ;loop if not opened
  1013.     call    KET    ;found, reopen WS
  1014.     jmp    mb9    ;go clean up
  1015.  
  1016. mb7:    call    UCZ    ;span last pathname
  1017.     call    KET    ;reopen WS
  1018. mb8:    call     UCQ    ;last chance
  1019.     call    SLOP    ;append \ if needed, try to open
  1020.     jnc    mb9    ;carry says open failed
  1021.     call    UCTL        ;type filename
  1022.     mov    dx,(offset nfil)
  1023.     jmp    FERM        ;type error message and quit
  1024.  
  1025. mb9:    call    UCL    ;get rid of last filename
  1026.     call    ENLF    ;get rid of bare filename
  1027.     mov    dx,P0    ;reset P1 and P2
  1028.     inc    dx
  1029.     mov    P1,dx
  1030.     mov    P2,dx
  1031.     mov    di,P3    ;save parsed filenames at p3 and following
  1032.     mov    es,WSEG    ;reload ES with WS base
  1033.     cld
  1034.     call    ficb
  1035.     call    ficb
  1036.     call    LCJ
  1037.     call    NU
  1038.     db    2
  1039.     dw    2573
  1040.     call    UCU    ;delimit tail once more
  1041.     nop
  1042.     nop        ;false exit filler
  1043.     nop
  1044.     call    LCQ    ;get its length
  1045.     call    PE
  1046.     call    UCJ
  1047.     call    LCF    ;reinsert it
  1048.     nop
  1049.     nop        ;false exit filler
  1050.     nop
  1051.     call    UCJ    ;p1 back to p0
  1052.     call    LFTW
  1053.     mov    bx,(offset DIRE)    ;REC input through disk
  1054.     mov    read,bx        ;REC compiler's I-O linkage
  1055.     call    INRE        ;initialize REC compiler RAM
  1056.     jmp    SSHOT        ;compile once from disk file
  1057.  
  1058. ;    Make a full pathname, try to open it
  1059.  
  1060. SLOP:    mov    bx,PY
  1061.     cmp    bx,PX
  1062.     jz    mb6    ;null path, try name by itself
  1063.     mov    al,-1[bx]    ;get last character
  1064.     cmp    al,':'
  1065.     jz    mb6    ;no \ needed if colon
  1066.     cmp    al,'\'
  1067.     jz    mb6    ;nor if last is \
  1068.     mov    byte ptr [bx],'\'
  1069.     inc    bx
  1070.     mov    PY,bx
  1071. mb6:    call    LCL    ;copy from PDL complement (lyG)
  1072.     call    GWI
  1073.     call    GA
  1074.     call    CONC    ;append path to filename
  1075.     call    CPIN    ;try opening it
  1076.     ret
  1077.  
  1078. ;    Move the environment string to the WS
  1079.  
  1080. MVENV:    call    NU    ;insert <CR,LF> at end
  1081.     db    2
  1082.     dw    2573
  1083.     call    UCI
  1084.     call    LCJ    ;null at p1
  1085.     cld
  1086.     mov    ax,ENVR    ;set up to move environment string to WS
  1087.     mov    di,P3
  1088.     mov    es,WSEG    ;get WS segment base before changing ds
  1089.     push    ds
  1090.     mov    ds,ax
  1091.     mov    si,0000    ;environment string starts at ax:0000
  1092. mb3:    lodsb
  1093.     stosb        ;movsb won't do, we have to test
  1094.     cmp    al,0
  1095.     jne    mb3    ;move while not a NUL
  1096.     cmp    byte ptr [si],0    ;is next a NUL too?
  1097.     jne    mb3    ;keep on moving if not
  1098.     pop    ds    ;done, restore ds
  1099.     mov    P3,di    ;update WS pointer
  1100.     ret
  1101.  
  1102. ;    return when separator found
  1103.  
  1104. fsep:    call    zsep
  1105.     jnz    fsep1
  1106.     ret
  1107. fsep1:    call    rech    ;read one character
  1108.     jmp    fsep
  1109.  
  1110. ;    Advance to a non blank character in the console
  1111. ;    buffer unless there is none, indicated by a 00.
  1112.  
  1113. zonb:    call    rech    ;read one character
  1114.     test    al,al
  1115.     jnz    zonb1
  1116.     ret
  1117. zonb1:    cmp    al,' '
  1118.     jz    zonb    ;zero or non-blank
  1119.     ret
  1120.  
  1121. ;    Generate a file control block in the manner of CCP.
  1122.  
  1123. ficb:    call    zonb    ;zero or non-blank
  1124.     push    ax
  1125.     jz    ficd
  1126.     sbb    al,'@'
  1127.     mov    dl,al    ;save possible disk id
  1128.     mov    bx,P2
  1129.     mov    bp,ds
  1130.     mov    ds,WSEG
  1131.     mov    al,(byte ptr[bx])
  1132.     mov    ds,bp
  1133.     cmp    al,':'
  1134.     jz    ficc
  1135.     xor    al,al
  1136.     jmp    ficd
  1137. ficc:    call    rech    ;get rid of colon
  1138.     pop    ax
  1139.     call    rech    ;get first of filename
  1140.     push    ax
  1141.     mov    al,dl
  1142. ficd:    stosb
  1143.     mov    cx,08
  1144.     pop    ax
  1145.     call    ffil
  1146.     call    fsep
  1147.     mov    cx,03
  1148.     cmp    al,'.'
  1149.     jnz    ficp
  1150.     call    rech    ;read one character
  1151.     call    ffil
  1152.     call    fsep
  1153.     jmp    ficq
  1154. ficp:    call    bfil
  1155. ficq:    mov    cx,04
  1156.     mov    ah,al
  1157.     mov    al,0
  1158.     jmp    kfil
  1159.  
  1160. ;    Fill a field
  1161.  
  1162. ffil0:    call    rech    ;read one character
  1163. ffil:    call    zsep
  1164.     jz    bfil
  1165.     cmp    al,'*'
  1166.     jz    qfil
  1167.     stosb
  1168.     loop    ffil0
  1169.     ret
  1170.  
  1171. ;    Block fill
  1172.  
  1173. qfil:    mov    ah,al
  1174.     mov    al,'?'
  1175.     jmp    kfil
  1176. bfil:    mov    ah,al
  1177.     mov    al,' '
  1178. kfil:    repnz    stosb
  1179.     mov    al,ah
  1180.     ret
  1181.  
  1182. ;    Fetch a character into a from command line
  1183.  
  1184. rech:    mov    bx,P1
  1185.     dec    bx    ;length is kept one back of p1
  1186.     mov    si,P2    ;both pointers before altering DS
  1187.     mov    bp,ds
  1188.     mov    ds,WSEG
  1189.     mov    al,(byte ptr[bx])    ;number of characters not taken out
  1190.     test    al,al
  1191.     mov    al,0DH    ;carriage return faked on empty buffer
  1192.     jz    recx
  1193.     dec    byte ptr[bx]
  1194.     mov    bx,si
  1195.     mov    al,byte ptr[bx]
  1196.     inc    bx
  1197.     mov    ds,bp
  1198.     mov    P2,bx
  1199. recx:    mov    ds,bp
  1200.     ret
  1201.  
  1202. ;    Set ZF if AL contains a separator
  1203.  
  1204. zsep:    test    al,al
  1205.     jz    zret
  1206.     cmp    al,0DH
  1207.     jz    zret
  1208.     cmp    al,' '
  1209.     jc    zscc    ;ctrl chars
  1210.     jz    zret
  1211.     cmp    al,'='
  1212.     jz    zret
  1213.     cmp    al,'_'
  1214.     jz    zret
  1215.     cmp    al,'.'
  1216.     jz    zret
  1217.     cmp    al,':'
  1218.     jz    zret
  1219.     cmp    al,';'
  1220.     jz    zret
  1221.     cmp    al,'<'
  1222.     jz    zret
  1223.     cmp    al,'>'
  1224. zret:    ret
  1225. zscc:    xor    al,al
  1226.     ret
  1227.  
  1228. ;    Memory usage stats
  1229.  
  1230. STATS:    mov    bx,P0
  1231.     mov    P1,bx
  1232.     mov    P2,bx        ;null at start of WS
  1233.     mov    ah,9        ;(09) write message
  1234.     mov    dx,(offset logo)
  1235.     int    bdos
  1236.     call    MVENV        ;copy env. string to the WS
  1237.     call    QU        ;use REC ops to show RAM usage
  1238.     dw    6
  1239.     db    'Code  '
  1240.     MOV    ax,C2
  1241.     MOV    cs:stt0,ax
  1242.     call    NU
  1243.     db    2
  1244. stt0    dw    0
  1245.     MOV    cs:stt1,cs
  1246.     call    NU
  1247.     db    2
  1248. stt1    dw    0
  1249.     call    RLCT
  1250.     call    QU
  1251.     dw    7
  1252.     db    '   CPL '
  1253.     mov    bp,C2
  1254.     sub    bp,C0
  1255.     call    RCTL
  1256.     call    QU
  1257.     dw    6
  1258.     db    'Data  '
  1259.     MOV    ax,PZ
  1260.     MOV    cs:stt2,ax
  1261.     call    NU
  1262.     db    2
  1263. stt2    dw    0
  1264.     MOV    cs:stt3,ds
  1265.     call    NU
  1266.     db    2
  1267. stt3    dw    0
  1268.     call    RLCT
  1269.     call    QU
  1270.     dw    7
  1271.     db    '   PDL '
  1272.     mov    bp,PZ
  1273.     sub    bp,(offset PD)+2
  1274.     call    RCTL
  1275.     call    QU
  1276.     dw    6
  1277.     db    'Extra '
  1278.     MOV    ax,P4
  1279.     MOV    cs:stt4,ax
  1280.     call    NU
  1281.     db    2
  1282. stt4    dw    0
  1283.     MOV    ax,WSEG
  1284.     MOV    cs:stt5,ax
  1285.     call    NU
  1286.     db    2
  1287. stt5    dw    0
  1288.     call    RLCT
  1289.     call    QU
  1290.     dw    7
  1291.     db    '   WS  '
  1292.     mov    bp,P4
  1293.     sub    bp,P0
  1294.     call    RCTL
  1295.     call    QU
  1296.     dw    6
  1297.     db    'Stack '
  1298.     MOV    cs:stt6,sp
  1299.     call    NU
  1300.     db    2
  1301. stt6    dw    0
  1302.     MOV    cs:stt7,ss
  1303.     call    NU
  1304.     db    2
  1305. stt7    dw    0
  1306.     call    RLCT
  1307.     call    QU
  1308.     dw    7
  1309.     db    '   STK '
  1310.     mov    bp,sp
  1311.     call    RCTL
  1312.     ret
  1313. TCRL:    call    NU
  1314.     db    2
  1315.     dw    2573
  1316.     call    UCT
  1317.     call    UCL
  1318.     ret
  1319. RLCT:    call    HX
  1320.     call    QU
  1321.     dw    1
  1322.     db    ':'
  1323.     call    CONC
  1324.     call    EXCH
  1325.     call    HX
  1326.     call    CONC
  1327.     call    QU
  1328.     dw    1
  1329.     db    'H'
  1330.     call    CONC
  1331. RLCT2:    call    CONC
  1332.     call    UCT
  1333.     call    UCL
  1334.     ret
  1335. RCTL:    mov    cx,2
  1336.     call    NARG
  1337.     mov    [bx],bp
  1338.     inc    bx
  1339.     inc    bx
  1340.     mov    PY,bx
  1341.     call    NS
  1342.     call    RLCT2
  1343.     call    TCRL
  1344.     ret
  1345.  
  1346. code    ends
  1347.  
  1348. ;    -----------------------------------------------------
  1349. ;    RAM memory which is required for the operation of REC
  1350. ;    -----------------------------------------------------
  1351.  
  1352. ;    =============
  1353. pdlist    segment
  1354.         org    0
  1355. dsbeg    db    02CH dup(?)
  1356. ENVR    dw    ?        ;here's the environment str address
  1357.     db    02EH dup(?)
  1358. TFCB    db    024H dup(?)
  1359. TBUF    db    ?
  1360.     org    0100H        ;origin of data in data segment
  1361. ;    =============
  1362.  
  1363. ;    Relay area for input and output subroutines.
  1364.  
  1365. read    dw    chin        ;character input for REC compiler
  1366. tyin    dw    chin        ;single character input for R
  1367. tyou    dw    chou        ;single character output for T
  1368.  
  1369. ;    Error message buffer
  1370.  
  1371. EMSGS    db    0DH,0AH
  1372. EMSG    dw    2020H
  1373.     db    ' overflow$'
  1374.  
  1375. ;    Prompt and crlf
  1376.  
  1377. bume    db    0DH,0AH,'REC87> $'
  1378. crlf    db    0DH,0AH,'$'
  1379. nfil    db    0DH,0AH,'File not found$'
  1380. usms    db    0DH,0AH,'Undefined subroutine '
  1381. usby    db    07H,'$ '
  1382.  
  1383. ;    Temporary storage used by the REC compiler.
  1384.  
  1385. XPD    dw    0000        ;colon jump back to left parenthesis
  1386. YPD    dw    0000        ;false predicate jump chain
  1387. ZPD    dw    0000        ;semicolon exit chain
  1388.  
  1389. ;    Pointers to the directories.
  1390.  
  1391. FXT    dw    FT        ;pointer to fixed operator directory
  1392. VRT    dw    VT        ;pointer to variable directory
  1393. SBT    dw    STB        ;pointer to subroutine directory
  1394. CMT    dw    CTB        ;pointer to compination directory
  1395. QUT    dw    QTB        ;pointer to "..." comb. table
  1396.  
  1397. ;    Pointers to the area of compiled subroutines.
  1398.  
  1399. C0    dw    ENDREC        ;lower limit of compile area
  1400. C1    dw    ENDREC        ;beginning of present compilation
  1401. C2    dw    0        ;upper limit of compile area
  1402.  
  1403. ;    Pointers to REC/MARKOV pushdown list.
  1404.  
  1405. PX    dw    PD+2        ;beginning of pushdown text
  1406. PY    dw    PD+2        ;end of pushdown text
  1407. PZ    dw    0        ;end of available pushdown space
  1408.  
  1409. ;    Workspace pointers.
  1410.  
  1411. P0    dw    0        ;beginning of workspace
  1412. P1    dw    0        ;beginning of marked segment
  1413. P2    dw    0        ;end of marked segment
  1414. P3    dw    0        ;end of text
  1415. P4    dw    0        ;end of workspace
  1416. WSEG    dw    0        ;WS segment address
  1417.  
  1418. ;    Number conversion and arithmetic buffers
  1419.  
  1420. FRST    db    0    ;first character of input string
  1421. ARG1    dw    0,0    ;8-byte buffer for digit collection
  1422. ARG1M    db    0
  1423. ARG1X    db    0
  1424. ARG1B    db    0
  1425. ARG1H    db    0
  1426. ARGHH    db    0
  1427. DCPT    db    0    ;decimal point flag and
  1428. DDCT    db    0    ;decimal digit count
  1429. BINXPT    equ    DCPT
  1430. ARG2    dw    0    ;alternate 8-byte buffer
  1431. ARG2B    dw    0
  1432. ARG2M    db    0,0,0
  1433. ARG2H    db    0
  1434. DCXPT    dw    0    ;decimal exponent
  1435. DXSG    db    0    ;flag for sign of decimal exponent
  1436. NSIZ    db    0    ;operand size in bytes
  1437.  
  1438. ;    I-O pointers.
  1439.  
  1440. RX    dw    0000
  1441. RY    dw    0000
  1442. RSEG    dw    0000
  1443. FLDES    dw    0000        ;source file handle
  1444.  
  1445. ;    Error flag.
  1446.  
  1447. ER    dw    0000
  1448.  
  1449. ;    Holder for return address from h
  1450.  
  1451. RTADDR    dw    0000
  1452.  
  1453. ;    ======= here is the table of definitions of REC operators =====
  1454.  
  1455. FT    dw    NOOP        ;blank
  1456.     dw    NOOP
  1457.     dw    RECOP        ; [exclm]    binary to hex string
  1458.     dw    HX
  1459.     dw    RECDQ        ; "    quoted expression
  1460.     dw    QU
  1461.     dw    RECOP        ; #    binary to decimal string
  1462.     dw    NS
  1463.     dw    RECOL        ; $    fetch a variable cell
  1464.     dw    VBLE
  1465.     dw    RECOP        ; %    restrict to one byte
  1466.     dw    PE
  1467.     dw    RECOL        ; &    exchange top numeric pair
  1468.     dw    EXCH
  1469.     dw    RECSQ        ; '    quoted expression
  1470.     dw    QU
  1471.     dw    RECLP        ; (
  1472.     dw    NOOP
  1473.     dw    RECRP        ; )
  1474.     dw    NOOP
  1475.     dw    RECOP        ; *    multiply
  1476.     dw    MPY
  1477.     dw    RECOP        ; +    add
  1478.     dw    SUM
  1479.     dw    NOOP        ; ,    separator like space
  1480.     dw    NOOP
  1481.     dw    RECMS        ; -    subtract
  1482.     dw    DIF
  1483.     dw    RECDD        ; .    decimal point
  1484.     dw    NU
  1485.     dw    RECOP        ; /    divide [remainder, quotient]
  1486.     dw    DVD
  1487.     dw    RECDD        ; 0    number
  1488.     dw    NU
  1489.     dw    RECDD        ; 1    number
  1490.     dw    NU
  1491.     dw    RECDD        ; 2    number
  1492.     dw    NU
  1493.     dw    RECDD        ; 3    number
  1494.     dw    NU
  1495.     dw    RECDD        ; 4    number
  1496.     dw    NU
  1497.     dw    RECDD        ; 5    number
  1498.     dw    NU
  1499.     dw    RECDD        ; 6    number
  1500.     dw    NU
  1501.     dw    RECDD        ; 7    number
  1502.     dw    NU
  1503.     dw    RECDD        ; 8    number
  1504.     dw    NU
  1505.     dw    RECDD        ; 9    number
  1506.     dw    NU
  1507.     dw    RECCO        ; :
  1508.     dw    NOOP
  1509.     dw    RECSC        ; ;
  1510.     dw    NOOP
  1511.     dw    RECOP        ; <    restrict workspace
  1512.     dw    BRA
  1513.     dw    RECPR        ; =    test equality of top pair
  1514.     dw    EQL
  1515.     dw    RECOL        ; >    open workspace
  1516.     dw    KET
  1517.     dw    RECPR        ; ?    test for error report
  1518.     dw    QM
  1519.     dw    RECP1        ; @    execute subroutine
  1520.     dw    AR
  1521.     dw    RECPR        ; A    advance pointer 1
  1522.     dw    UCA
  1523.     dw    RECPR        ; B    retract pointer 1
  1524.     dw    UCB
  1525.     dw    RECOP        ; C    compile
  1526.     dw    UCC
  1527.     dw    RECOP        ; D    delete text
  1528.     dw    UCD
  1529.     dw    RECPL        ; E    equality between WS and PD
  1530.     dw    UCE
  1531.     dw    RECPL        ; F    find specified text
  1532.     dw    UCF
  1533.     dw    RECOP        ; G    fetch a block from memory
  1534.     dw    GA
  1535.     dw    RECPR        ; H    ASCII hex to binary
  1536.     dw    HE
  1537.     dw    RECOL        ; I    insert
  1538.     dw    UCI
  1539.     dw    RECOL        ; J    jump to front
  1540.     dw    UCJ
  1541.     dw    RECOP        ; K    call CP/M, keep (dx), put value
  1542.     dw    CPM
  1543.     dw    RECOL        ; L    erase top of PDL
  1544.     dw    UCL
  1545.     dw    RECPR        ; M    compare PDL and workspace
  1546.     dw    UCM
  1547.     dw    RECPR        ; N    numerical comparison
  1548.     dw    UCN
  1549.     dw    RECPR        ; O    decimal ASCII string to binary
  1550.     dw    UCO
  1551.     dw    RECOP        ; P    put block into buffered memory
  1552.     dw    UCP
  1553.     dw    RECOL        ; Q    put workspace segment on PD
  1554.     dw    UCQ
  1555.     dw    RECOP        ; R    read from keyboard
  1556.     dw    UCR
  1557.     dw    RECOP        ; S    store block in memory
  1558.     dw    SA
  1559.     dw    RECOL        ; T    write on screen
  1560.     dw    UCT
  1561.     dw    RECPR        ; U    search, yielding interval
  1562.     dw    UCU
  1563.     dw    RECPR        ; V    U, including endpoints
  1564.     dw    UCV
  1565.     dw    RECOP        ; W    write on printer
  1566.     dw    UCW
  1567.     dw    RECO1        ; X    call library operator
  1568.     dw    LIBO
  1569.     dw    RECPR        ; Y    recover previous position of p1
  1570.     dw    UCY
  1571.     dw    RECOL        ; Z    pointer 2 to end of text
  1572.     dw    UCZ
  1573.     dw    RECCM        ; [    comment
  1574.     dw    NOOP
  1575.     dw    RECOP        ; \    insert single byte in pair
  1576.     dw    IP
  1577.     dw    RECOP        ; ]
  1578.     dw    NOOP
  1579.     dw    RECOL        ; ^    increment top argument
  1580.     dw    INCR
  1581.     dw    RECOP        ; _    exit to monitor
  1582.     dw    boot
  1583.     dw    RECPR        ; `    true for waiting character
  1584.     dw    CHAW
  1585.     dw    RECPR        ; a    segment forward from p1
  1586.     dw    LCA
  1587.     dw    RECPR        ; b    segment backward from p2
  1588.     dw    LCB
  1589.     dw    RECOP        ; c    create block on PDL
  1590.     dw    BLOK
  1591.     dw    RECPR        ; d    decrement but skip on zero
  1592.     dw    decR
  1593.     dw    RECPR        ; e    extend workspace
  1594.     dw    LCE
  1595.     dw    RECPR        ; f    block fill
  1596.     dw    LCF
  1597.     dw    RECOP        ; g    non-incrementing byte fetch
  1598.     dw    GB
  1599.     dw    RECOP        ; h    store/restore machine state
  1600.     dw    MST
  1601.     dw    RECOP        ; i    input from designated port
  1602.     dw    LCI
  1603.     dw    RECOL        ; j    null interval at p1
  1604.     dw    LCJ
  1605.     dw    RECOP        ; k    call CP/M: no returned values
  1606.     dw    CPML
  1607.     dw    RECOP        ; l    put pz on PDL
  1608.     dw    Lcl
  1609.     dw    RECOP        ; m    set aside top argument
  1610.     dw    LCM
  1611.     dw    RECOL        ; n    recover set-aside argument
  1612.     dw    LCN
  1613.     dw    RECOP        ; o    output from designated port
  1614.     dw    LCO
  1615.     dw    RECOL        ; p    put px, py-px on PDL
  1616.     dw    GXS
  1617.     dw    RECOL        ; q    put p1, p2-p1 on PDL
  1618.     dw    LCQ
  1619.     dw    RECOP        ; r    indirect replacement of address
  1620.     dw    IND
  1621.     dw    RECOP        ; s    store block in memory wrt limit
  1622.     dw    LCS
  1623.     dw    RECOP        ; t    type out indicated interval
  1624.     dw    LCT
  1625.     dw    RECOP        ; u    incrementing byte fetch
  1626.     dw    GBI
  1627.     dw    RECOP        ; v    incrementing byte store
  1628.     dw    SAI
  1629.     dw    RECOP        ; w    store workspace header
  1630.     dw    LCW
  1631.     dw    RECP1        ; x    call library predicate
  1632.     dw    LIBP
  1633.     dw    RECOP        ; y    fetch byte pair to PDL incr org
  1634.     dw    GWI
  1635.     dw    RECOL        ; z    null interval at p2
  1636.     dw    LCZ
  1637.     dw    LBR        ; {    start a definition string
  1638.     dw    NOOP
  1639.     dw    RECOP        ; |    concatinate top two arguments
  1640.     dw    CONC
  1641.     dw    RECOP        ; }    end a definition string
  1642.     dw    NOOP
  1643.     dw    RECOP        ; ~    complement or negate top arg
  1644.     dw    COMP
  1645.     dw    RECOP        ; del
  1646.     dw    NOOP
  1647.  
  1648. ;    Table of often-used combinations to compile as single
  1649. ;    operators or predicates.
  1650.  
  1651. CTB    db    'Ez'        ;to the right if same
  1652.     dw    EZE
  1653.     db    'JZ'        ;span text
  1654.     dw    SPAN
  1655.     db    'z<'        ;null WS at p2
  1656.     dw    ZCL
  1657.     db    'Z>'        ;reopen with p2 at end
  1658.     dw    ZOP
  1659.     db    'Jj'        ;p1 and p2 at p0
  1660.     dw    BEG
  1661.     db    'Z<'        ;restrict from p1 to p3
  1662.     dw    UZCL
  1663.     db    'pG'        ;duplicate PDL argument
  1664.     dw    DUPP
  1665.     db    'ED'        ;delete if same
  1666.     dw    EDE
  1667.     db    'J>'        ;open with p1 at old p0
  1668.     dw    JOP
  1669.     db    'Iz'        ;insert and collapse
  1670.     dw    IZE
  1671.     db    'jJ'        ;p1 and p2 to p0 and p1
  1672.     dw    LJUJ
  1673.     db    '><'        ;reopen and restrict
  1674.     dw    OPCL
  1675.     db    '^^'        ;increase by 2
  1676.     dw    INTW
  1677.     db    'QD'        ;copy and delete
  1678.     dw    QUDE
  1679.     db    'FD'        ;find and delete
  1680.     dw    EFDE
  1681.     db    'nL'        ;lift from PDL complement
  1682.     dw    ENLF
  1683.     db    '&S'        ;exch args and store
  1684.     dw    XSTO
  1685.     db    'LL'        ;lift twice
  1686.     dw    LFTW
  1687.     db    '$r'        ;contents of var cell
  1688.     dw    VREP
  1689.     db    '$S'        ;save in var cell
  1690.     dw    VSTO
  1691.     db    '&L'        ;lift lower
  1692.     dw    XLFT
  1693.     db    'qL'        ;p1 to PDL
  1694.     dw    GTP1
  1695.     db    'J<'        ;restrict from p0
  1696.     dw    JCL
  1697.     db    'I<'        ;insert and restrict
  1698.     dw    ICL
  1699.     db    'TL'        ;type and lift
  1700.     dw    UCTL
  1701.     db    'Qm'        ;Copy WS to PDL complement
  1702.     dw    QUEM
  1703.     dw    0000        ;end-of-table marker
  1704.  
  1705. QTB    db    '=',1        ;compare pdl to program const
  1706.     dw    QEQL
  1707.     db    'E',1        ;compare WS to program const
  1708.     dw    QUCE
  1709.     db    'F',1        ;find program const in WS
  1710.     dw    QUCF
  1711.     db    'I',0        ;insert program const in WS
  1712.     dw    QUCI
  1713.     db    'M',1        ;program const is upper bd in lex comp
  1714.     dw    QUCM
  1715.     db    'U',1        ;find program const in WS, excl bounds
  1716.     dw    QUCU
  1717.     db    'V',1        ;find program const in WS, incl bounds
  1718.     dw    QUCV
  1719.     dw    0
  1720.  
  1721. VT    dw    021H dup(?)    ;REC-defined subroutine table & vars.
  1722. STB    dw    05FH dup(?)
  1723. PD    dw    0        ;beginning of PDL
  1724.  
  1725. logo    db    0DH,0AH,'       REC(8086)/ICUAP',0DH,0AH
  1726.     db    'Universidad Autonoma de Puebla',0DH,0AH
  1727.     db    '      September 11, 1990',0DH,0AH,0AH,'$'
  1728.  
  1729. dlst    db    0
  1730.  
  1731. pdlist    ends
  1732.  
  1733. ;    =============
  1734. stack    segment    STACK
  1735.     org    0000H        ;origin of stack segment
  1736. ;    =============
  1737.  
  1738. STKB    dw    0
  1739. STKE    dw    0
  1740. stack    ends
  1741.  
  1742.  
  1743. ;    end
  1744.