home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol214 / rec86f.lbr / PDL86F.AQ6 / PDL86F.A86
Encoding:
Text File  |  1986-02-09  |  22.5 KB  |  813 lines

  1. ;    =======================================================
  2. ;
  3. ;    REC module for the operators and predicates pertaining
  4. ;    to the pushdown list, other than the most important
  5. ;    ones already contained in the REC nucleus.  These
  6. ;    comprise:
  7. ;
  8. ;        comparison
  9. ;
  10. ;            =    equality
  11. ;
  12. ;        modification of arguments
  13. ;
  14. ;            H    hex ASCII string to binary
  15. ;            [exclm]    binary to hex ASCII string
  16. ;            &    exchange top arguments
  17. ;            |    concatinate top arguments
  18. ;
  19. ;        block movements
  20. ;
  21. ;            G    fetch a block from memory
  22. ;            g    address fetch
  23. ;            r    replace address by contents
  24. ;            u    incrementing byte fetch
  25. ;            y    incrementing word fetch
  26. ;            P    put buffer block in memory
  27. ;            S    store block in memory
  28. ;            s    store into buffer
  29. ;            v    incrementing byte store
  30. ;            m    move arg to end of PDL space
  31. ;            n    recover arg from end of PDL
  32. ;            h    store/restore machine state
  33. ;
  34. ;        generate pointers
  35. ;
  36. ;            c    reserve block, generate pointer
  37. ;            p    put px, py-px on PDL
  38. ;            l    put pz on PDL
  39. ;            $    form addr of variable cell
  40. ;
  41. ;    -------------------------------------------------------
  42. ;    Version of REC released during the summer school, 1980
  43. ;    -------------------------------------------------------
  44. ;    8086 version with separate segments for code, PDL, WS.
  45. ;    -------------------------------------------------------
  46. ;
  47. ;          PDL86  -  Copyright (C) 1982, 1984
  48. ;        Universidad Autonoma de Puebla
  49. ;             All Rights Reserved
  50. ;
  51. ;         [Harold V. McIntosh, 25 April 1982]
  52. ;         [Gerardo Cisneros, 8 February 1984]
  53. ;
  54. ;    May 29, 1983 - & exchanges arbitrary arguments
  55. ;    May 29, 1983 - ~ discontinued; use m&n instead
  56. ;    May 29, 1983 - ~ Complement or Negate top element
  57. ;    May 29, 1983 - N for Numerical comparison on PDL
  58. ;    July 7, 1983 - $ with char arg gets subroutine addr
  59. ;    January 23, 1984 - at comp:, <cmp ax,> is <cmp cx,>
  60. ;    February 8, 1984 - separate segments (GCS)
  61. ;    May 9, 1984 - h stores/restores machine state (GCS)
  62. ;    May 22, 1984 - arithmetic operators moved to ATH and FLT (GCS)
  63. ;    May 23, 1984 - H and exclm handle any length (GCS)
  64. ;    May 31, 1984 - PDL becomes 1st module of REC86F.CMD -GCS
  65. ;    18 June 1984 - n quits on empty PDL complement - GCS
  66. ;    3 July 1984 - entry points for pG, $S and $r - GCS
  67. ;    15 Aug 1984 - E.P.s for nL and &S - GCS
  68. ;    =======================================================
  69.  
  70. ;    =============
  71.     org    0000H
  72. ;    =============
  73.  
  74.  
  75.     jmp    MAIN    ;<===============================<<<
  76.  
  77.  
  78. ;    =======================================================
  79. ;    A collection of subroutines for two-byte arithmetic,
  80. ;    including loading and storage of the 8080 registers
  81. ;    from the pushdown list.
  82. ;    =======================================================
  83.  
  84. ;    -------------------------------------------------------
  85. ;    Load and store subroutines for 2-byte arithmetic.
  86. ;    -------------------------------------------------------
  87.  
  88. ;    Push a two-byte value onto the PDL.  The value to be
  89. ;    pushed should be placed on the 8080's stack before
  90. ;    calling PUTW.
  91.  
  92. PUTW:    mov    cx,2        ;two bytes are required
  93.     call    NARG        ;close old variable, reserve space
  94.     mov    bp,sp
  95.     mov    ax,2[bp]
  96.     mov    [bx],ax        ;store low order byte
  97.     inc    bx        ;on to high order destination
  98.     inc    bx        ;always leave pointer in good condition
  99.     mov    PY,bx        ;close top argument
  100.     ret    2
  101.  
  102. ;    (&) Exchange top two arguments, assumed two-byte.
  103.  
  104. EXCH:    mov    ax,PY
  105.     mov    bx,PX        ;org1
  106.     sub    ax,bx        ;siz1
  107.     mov    dx,-2[bx]    ;org2
  108.     lea    cx,-2[bx]
  109.     sub    cx,dx        ;siz2
  110.     cmp    ax,cx
  111.     jnz    XTNE
  112.     jcxz    XTRE
  113. XTEQ:    mov    al,[bx]
  114.     xchg    bx,dx
  115.     mov    ah,[bx]
  116.     mov    [bx],al
  117.     xchg    bx,dx
  118.     mov    [bx],ah
  119.     inc    bx
  120.     inc    dx
  121.     loop    XTEQ
  122. XTRE:    ret
  123. XTNE:    push    cx
  124.     push    dx
  125.     push    bx
  126.     push    ax
  127.     push    dx
  128.     call    NARG
  129.     mov    ax,ds
  130.     mov    es,ax
  131.     cld
  132.     mov    di,bx
  133.     pop    si
  134.     repnz    movs    byte [di],[si]
  135.     pop    cx
  136.     pop    si
  137.     pop    di
  138.     push    di
  139.     repnz    movs    byte [di],[si]
  140.     pop    word ptr [di]
  141.     lea    di,2[di]
  142.     mov    si,PX
  143.     mov    PX,di
  144.     pop    cx
  145.     repnz    movs    byte [di],[si]
  146.     mov    PY,di
  147.     ret
  148.  
  149. ;    Load top two arguments into the machine's stack.  In
  150. ;    reality so many permutations exist for places to put
  151. ;    the arguments as they are taken off the REC stack that
  152. ;    they are simply transferred to the 8080 stack, to be
  153. ;    popped into the desired registers on return from the
  154. ;    corresponding call.  It is assumed that all quantities
  155. ;    involved in these transactions are of two bytes.  A
  156. ;    sequence of entry points is provided so as to pop off
  157. ;    one or two arguments.
  158.  
  159. TWOL:    mov    bx,PX
  160.     pop    bp        ;entry for two args
  161.     push    word ptr [bx]
  162.     push    bp
  163.     call    UCL        ;pop argument, put px in (bx)
  164. ONEL:    pop    bp        ;continue, or entry for one argument
  165.     push    word ptr [bx]
  166.     push    bp
  167.     jmp    UCL        ;pop the last argument, quit
  168.  
  169. ;    -------------------------------------------------------
  170. ;    Conversion between binary and hexadecimal ASCII strings
  171. ;    -------------------------------------------------------
  172.  
  173. ;    Return if not hexadecimal. A unchanged if not hex, else
  174. ;    reduced to binary.
  175.  
  176. RNH:    cmp    al,'G'        ;no hex characters beyond F
  177.     jnb    RH2
  178.     cmp    al,'A'        ;hex letters equal A or beyond
  179.     jb    RH1
  180.     sub    al,'7'        ;compensate the gap between 9 and A
  181.     ret
  182. RH1:    jmp    RND
  183. RH2:    inc    sp
  184.     inc    sp
  185.     ret
  186.  
  187. ;    (H) Convert a hex ASCII string on the PDL into binary.
  188. ;    If the length of the string is n, the result will have
  189. ;    int((n+1)/2) bytes, stored in Intel form: the least
  190. ;    significant byte in the lowest addressed location.
  191.  
  192. HE:    mov    cx,PY        ;compute length of string
  193.     mov    si,PX        ;while saving pointers
  194.     sub    cx,si
  195.     jz    H4        ;leave null strings alone
  196.     mov    bp,cx        ;save byte count
  197.     cld
  198. H0:    lods    byte ptr [si]    ;check that all characters
  199.     call    RNH        ;are hex digits, return false if not
  200.     loop    H0
  201.     mov    cx,bp
  202.     inc    cx        ;compute length of final number
  203.     shr    cx,1
  204.     mov    si,PX        ;reload PX to process the hex string
  205.     mov    bp,si        ;copy of PX to be used later
  206.     mov    bx,si        ;another copy as pointer for result
  207.     mov    di,cx        ;copy of byte count to be used later
  208.     mov    dl,0
  209.     jnc    H2        ;start in the middle if length odd
  210. H1:    lods    byte ptr [si]
  211.     call    RNH        ;reduce to binary
  212.     shl    al,1        ;multiply by 16
  213.     shl    al,1
  214.     shl    al,1
  215.     shl    al,1
  216.     mov    dl,al        ;save it while getting next nibble
  217. H2:    lods    byte ptr [si]
  218.     call    RNH
  219.     or    al,dl        ;put nibbles together
  220.     mov    [bx],al        ;and store on PDL
  221.     inc    bx        ;keep pointing to the next byte
  222.     loop    H1
  223.     mov    PY,bx        ;update PY
  224.     call    HXC        ;turn the string around
  225. H4:    jmp    SKP        ;return TRUE
  226.  
  227. ;    Turn around string of (DI) bytes starting at (BP) and
  228. ;    ending at (BX)-1
  229.  
  230. HXC:    dec    bx        ;highest byte
  231.     mov    cx,di        ;total byte count
  232.     shr    cx,1        ;half of number of bytes
  233.     jcxz    H5
  234. H3:    mov    al,[bx]
  235.     xchg    ds:[bp],al
  236.     mov    [bx],al
  237.     dec    bx
  238.     inc    bp
  239.     loop    H3
  240. H5:    ret
  241.  
  242. ;    ([exclm])  Convert an n-byte binary number into an ASCII
  243. ;    string of length 2n.  The high order byte is assumed to be
  244. ;    in the highest-addressed location.
  245.  
  246. HX:    mov    cx,PY        ;compute lenght of number
  247.     mov    si,cx
  248.     mov    bp,PX        ;while saving pointers in other
  249.     sub    cx,bp        ;registers
  250.     jnz    HX0
  251.     ret            ;leave null strings alone
  252. HX0:    mov    di,cx
  253.     shl    cx,1        ;twice as many bytes will be made
  254.     call    OARG        ;verify availability of space
  255.     mov    PY,bx        ;update PY right away
  256.     mov    cx,di        ;restore old count
  257.     std            ;conversion proceeds backwards
  258.     dec    si        ;last byte is one below original PY
  259. HX1:    lods    byte ptr [si]    ;get the byte
  260.     mov    ah,al        ;make a copy
  261.     call    HSA        ;produce digit from high nibble
  262.     mov    al,ah        ;back to AL
  263.     call    HSB        ;produce digit from low nibble
  264.     loop    HX1
  265.     shl    di,1        ;prepare to turn string around
  266.     mov    bx,PY
  267.     jmps    HXC
  268.  
  269. HSA:    ror    al,1        ;shift byte right four bits
  270.     ror    al,1        ;
  271.     ror    al,1        ;
  272.     ror    al,1        ;
  273. HSB:    and    al,0FH        ;mask in right nibble
  274.     add    al,90H        ;prepare for some carries from <daa>
  275.     daa            ;create gap if nibble beyond 10
  276.     adc    al,40H        ;code for @ if we have a letter
  277.     daa            ;decide 3 for digit, 4 for letter
  278.     dec    bx        ;get pointer ready for deposit
  279.     mov    [bx],al        ;record the ASCII digit
  280.     ret
  281.  
  282. ;    -------------------------------------------------------
  283. ;    Fetch and store bytes, addresses, and blocks to and fro
  284. ;    between the PDL and the memory.  The following chart
  285. ;    shows the relation between all the different operators
  286. ;    which are available.
  287. ;
  288. ;                byte    word    block
  289. ;                ----    ----    -----
  290. ;
  291. ;    replace            -    r    G
  292. ;    fetch, nonincrement    g    -    -
  293. ;    fetch, increment    u    y    -
  294. ;
  295. ;    store            -    -    S
  296. ;    store, increment    -    -    v
  297. ;    store w.r.t. limit    -    -    s
  298. ;    store into buffer    -    -    P
  299. ;
  300. ;    variable head cell    -    $    -
  301. ;
  302. ;    The main operators for saving and fetching variables
  303. ;    are G and S.  The remainder were especially chosen
  304. ;    on the one hand to scrutinize the memory under REC
  305. ;    control, and on the other to give the widest possible
  306. ;    latitude in defining variables in applications of REC.
  307. ;
  308. ;    The following chart shows how to employ variables:
  309. ;
  310. ;        'data' [var#] $ S        define 2-byte variable
  311. ;         [var#] $ r            fetch 2-byte variable
  312. ;        'data' ml [var#] $ S    save fixed variable
  313. ;         [var#] $ ryG        fetch fixed variable
  314. ;        'data' [var#] $rs        redefine existing fixed var
  315. ;         kc Lml [var#] $ S        create k-byte buffered variable
  316. ;         kc [var#] $ S        alternative k-byte buffered var
  317. ;        'data' [var#] $r P        redefine buffered variable
  318. ;         [var#] $ ryLyG        fetch buffered variable
  319. ;
  320. ;    Memory can be examined bytewise with the following
  321. ;    combinations:
  322. ;
  323. ;        org g        fetch a byte, keep origin
  324. ;        org u        autoincrementing byte fetch
  325. ;        org v        autoincrementing byte store
  326. ;        org (g  ... v:;)    read, modify, store, ready next
  327. ;        o1 o2 (u~...v&:;)    move from o1 to o2
  328. ;
  329. ;    -------------------------------------------------------
  330.  
  331. ;    (g) (u)  Fetch a byte from memory and leave on PDL. The
  332. ;    sequence <org, g> leaves <org, (org)[1 byte]> on PDL.
  333. ;    The sequence <org, u> leaves <org+1, (org)[1 byte]> on
  334. ;    PDL.
  335.  
  336. GB:    mov    bx,PX        ;/g/ pointer to top argument
  337.     push    word ptr [bx]        ;fetch low byte of origin
  338.     jmp    GBJ        ;if the origin is not to be incremented
  339. GBI:    mov    bx,PX        ;/u/ pointer to arg, which is org
  340.     push    word ptr [bx]        ;fetch low byte of origin
  341.     inc    word ptr [bx]
  342. GBJ:    call    ESLD        ;get segment address
  343.     mov    cx,1        ;require space for one byte
  344.     call    NARG        ;close old arg, check space, open new
  345.     pop    dx        ;here's the origin we saved
  346.     xchg    bx,dx
  347.     mov    al,es:[bx]
  348.     xchg    bx,dx        ;fetch the byte there
  349.     mov    [bx],al        ;store on the PDL
  350.     inc    bx        ;pointer always ready for next byte
  351.     mov    PY,bx        ;right deliniter of argument
  352.     ret
  353.  
  354. ;    (y)  Fetch two bytes from memory and leave on PDL.
  355. ;    The sequence <org, y> leaves <org+2, (org)[2 bytes]>
  356. ;    on PDL.
  357.  
  358. GW:    mov    bx,PX        ;/ / pointer to the argument
  359.     push    word ptr [bx]        ;low byte of origin
  360.     jmp    GWJ        ;common continuation of gw, gwi
  361. GWI:    mov    bx,PX        ;/y/ pointer to the argument
  362.     push    word ptr [bx]        ;place low byte in A
  363.     add    word ptr [bx],2        ;origin to be incremented by 2
  364. GWJ:    call    ESLD        ;get segment address
  365.     mov    cx,2        ;require space for two bytes
  366.     call    NARG        ;close old arg, check space, open new
  367.     pop    dx        ;now we're ready for that origin
  368.     xchg    bx,dx
  369.     mov    ax,es:[bx]
  370.     xchg    bx,dx        ;fetch the byte sitting there
  371.     mov    [bx],ax        ;and store it on PDL
  372.     inc    bx
  373.     inc    bx        ;keep the pointer moving along
  374.     mov    PY,bx        ;value's finished, store its end
  375.     ret
  376.  
  377. ;    (G)  Fetch a block from memory, leave on PDL.
  378. ;    <org,siz, G> leaves (org, ...) on PDL.
  379.  
  380. GA:    call    CXLD        ;load siz into (cx)
  381.     call    OARG        ;reuse the argument, but with siz bytes
  382.     call    ESLD        ;get segment base
  383.     mov    si,[bx]        ;pick up source address too
  384.     cld
  385.     mov    di,bx
  386.     mov    bp,ds
  387.     mov    ax,es
  388.     mov    ds,ax
  389.     mov    es,bp
  390.     repnz    movs    byte [di],[si]
  391.     mov    ds,bp        ;restore data segment
  392.     mov    PY,di        ;(bx) holds the destination terminator
  393.     ret
  394.  
  395. ;    (pG)  Make a copy of the last argument, a combination
  396. ;    which is compiled as a single operator
  397.  
  398. DUP:    mov    cx,PY    ;compute size of current top
  399.     sub    cx,PX
  400.     call    NARG    ;check availability of space
  401.     mov    ax,ds
  402.     mov    es,ax    ;prepare for move
  403.     cld
  404.     mov    si,dx    ;old PX is in DX
  405.     mov    di,bx    ;new PX is in BX
  406.     repnz    movs    byte [di],[si]    ;count still in  CX
  407.     mov    PY,di    ;note new argument end
  408.     ret
  409.  
  410. ;    (S)  Store a block forward from the designated memory
  411. ;    location.  <'data' org S> stores 'data' starting at
  412. ;    org; leaves no residue on the PDL.
  413.  
  414. XSTO:    call    EXCH        ;entry point for &S
  415.     jmps    SA
  416.  
  417. VSTO:    call    VBLE        ;entry pt for combination $S
  418.  
  419. SA:    call    CXLD        ;fetch destination origin
  420.     mov    di,cx        ;save it for a while
  421.     mov    si,PX
  422.     mov    cx,PY
  423.     sub    cx,si
  424.     cld
  425.     repnz    movs    byte [di],[si]
  426.     jmp    UCL        ;pop the second argument too
  427.  
  428. ;    (v)  Store a block, leaving incremented address.
  429. ;    <org,'data' v> leaves org+size['data'] on PDL, stores
  430. ;    'data' starting from org.
  431.  
  432. SAI:    mov    si,PX
  433.     mov    cx,PY
  434.     sub    cx,si        ;determine length of data
  435.     call    UCL        ;pop top argument, exposing second
  436.     call    ESLD        ;get segment address
  437.     mov    di,[bx]        ;(bx) has px, which is destn address
  438.     mov    ax,si
  439.     add    ax,cx
  440.     cmp    di,ax
  441.     jb    LVB
  442.     cld
  443.     repnz    movs    byte [di],[si]
  444.     mov    [bx],di
  445.     ret
  446. LVB:    std
  447.     add    si,cx
  448.     add    di,cx
  449.     mov    [bx],di
  450.     dec    si
  451.     dec    di
  452.     repnz    movs    byte [di],[si]
  453.     ret
  454.  
  455. ;    (s)  Store into an area of limited size. The sequence
  456. ;    <'data' org s> will store 'data' beginning at org+2,
  457. ;    supposing that siz('data') is less than or equal to
  458. ;    (org, org+1).  In either event no residue is left, but
  459. ;    an error notation is generated if the data doesn't fit.
  460. ;    No data at all is stored if all will not fit.  If it
  461. ;    matters to know how much of the space was used, the
  462. ;    operator P should probably be used instead.
  463.  
  464. LCS:    call    CXLD        ;fetch destination origin
  465.     mov    bx,cx        ;save it while calling psiz
  466.     mov    si,PX
  467.     mov    cx,PY
  468.     sub    cx,si        ;determine length of data
  469.     mov    ax,es:[bx]        ;low byte of capacity
  470.     cmp    ax,cx
  471.     jnb    LST
  472.     call    UCL
  473.     call    RER        ;note error, return if it won't fit
  474. LST:    cld
  475.     inc    bx
  476.     inc    bx
  477.     mov    di,bx
  478.     repnz    movs    byte [di],[si]
  479.     jmp    UCL        ;pop second argument
  480.  
  481. ;    (P)  Store into a buffer and note length.  Used to
  482. ;    store data of variable length into an area whose
  483. ;    maximum length is fixed.  The buffer has the form
  484. ;
  485. ;       /available/used/data/data/.../data/.../end/
  486. ;
  487. ;    The sequence <'data' org P> will store the data
  488. ;    in the buffer beginning at org. (org, org+1) holds
  489. ;    the maximum length of data that may be stored in the
  490. ;    buffer, (org+2, org+3) is siz('data'), and 'data' is
  491. ;    stored from org+4 onward if it will fit.  If it will
  492. ;    not, P is a noop and error is set.
  493.  
  494. UCP:    call    CXLD        ;pointer to destination
  495.     mov    bx,cx        ;save destination while calling psiz
  496.     mov    si,PX
  497.     mov    cx,PY
  498.     sub    cx,si        ;load (cx) with length of data
  499.     inc    cx        ;data has to appear two bytes larger
  500.     inc    cx        ;to include cell showing its size
  501.     mov    ax,es:[bx]        ;low byte of destination capacity
  502.     inc    bx        ;
  503.     inc    bx        ;
  504.     cmp    ax,cx
  505.     jnb    UP1
  506.     call    RER        ;capacity exceeded: mark error, return
  507. UP1:    dec    cx        ;we want to store the true size
  508.     dec    cx        ;subtract out the two byte margin
  509.     mov    es:[bx],cx        ;low byte into usage cell
  510.     inc    bx        ;just keep moving along
  511.     inc    bx        ;ready to start moving data
  512.     cld
  513.     mov    di,bx
  514.     mov    ax,ds
  515.     mov    es,ax
  516.     repnz    movs    byte [di],[si]
  517.     jmp    UCL        ;lift second argument, leave nothing
  518.  
  519. ;    (r)  Replace address on top of pdl by its contents.
  520.  
  521. VREP:    call    VBLE        ;entry point for combination $r
  522. IND:    call    ESLD        ;get segment address
  523.     mov    dx,[bx]        ;load word
  524.     xchg    bx,dx        ;(bx) now has top argument
  525.     mov    ax,es:[bx]        ;indirect address
  526.     xchg    bx,dx        ;address of top argument again
  527.     mov    [bx],ax        ;store low indirect byte
  528.     add    bx,2        ;set PY in case old arg had 4 bytes
  529.     mov    PY,bx
  530.     ret
  531.  
  532. ;    ($)  Generate the address of the nth cell in the array
  533. ;    of variables, which is a block of four-byte addresses.
  534. ;    These cells may be used to store data directly - for
  535. ;    example counters or addresses - or indirectly through
  536. ;    pointers to the actual location of the data.  By giving
  537. ;    a one-byte character argument, <'x'$>, the location where
  538. ;    the address of subroutine x is stored may be obtained.
  539.  
  540. VBLE:    mov    bx,PX        ;pointer to argument
  541.     mov    cx,PY
  542.     sub    cx,bx
  543.     cmp    cx,2
  544.     jz    VBLF
  545.     mov    cx,2
  546.     call    OARG        ;reuse old arg with size 2
  547.     mov    bx,PX
  548.     mov    al,[bx]
  549.     mov    ah,0
  550.     jmp    VBLG
  551. VBLF:    mov    ax,[bx]
  552. VBLG:    add    ax,ax
  553.     add    ax,ax
  554.     add    ax,VRT
  555.     mov    [bx],ax
  556.     add    bx,2
  557.     mov    PY,bx
  558.     ret
  559.  
  560. ;    (l)  Load pz onto PDL.
  561.  
  562. LCL:    push    PZ        ;putw requires arg on 8080 stack
  563.     call    PUTW        ;record two-byte argument
  564.     ret            ;can't use simply <jmp putw>
  565.  
  566. ;    (m)  Set aside top argument on PDL.  It is moved to the
  567. ;    other end of the array reserved for the PDL, which can
  568. ;    be used as a temporary storage stack without name.  The
  569. ;    mechanism by which pz is moved and the block size is
  570. ;    recorded makes this an attractive mechanism to create
  571. ;    storage space for REC variables.
  572.  
  573. LCM:    mov    si,PY
  574.     mov    cx,si
  575.     sub    cx,PX        ;get length of top argument
  576.     push    cx
  577.     call    UCL        ;pop top argument
  578.     mov    di,PZ        ;load destination origin
  579.     std
  580.     dec    si
  581.     dec    di
  582.     mov    ax,ds
  583.     mov    es,ax
  584.     repnz    movs    byte [di],[si]
  585.     lea    bx,-1[di]
  586.     mov    PZ,bx
  587.     pop    word ptr [bx]        ;recover length
  588.     ret
  589.  
  590. ;    (n)  Recover segment which was set aside.
  591.  
  592. LCN:    mov    cx,ZE        ;there won't be any net length change
  593.     call    NARG        ;close old argument, ready for new
  594.     mov    di,bx        ;place destination origin in (dx)
  595.     mov    PY,di        ;leave null string in case of error
  596.     mov    bx,PZ        ;place source origin in (bx)
  597.     mov    cx,[bx]        ;place length in cx
  598.     cmp    cx,0FFFFH    ;see whether PDL complement is empty
  599.     jnz    lcn1
  600.     call    RER        ;it is, quit after recording error
  601. lcn1:    lea    si,2[bx]
  602.     cld
  603.     mov    ax,ds
  604.     mov    es,ax
  605.     repnz    movs    byte [di],[si]
  606.     mov    PY,di        ;end of destination is end of argument
  607.     mov    PZ,si        ;update pz
  608.     ret
  609.  
  610. ;    (nL)  Lift from PDL complement
  611.  
  612. ENLF:    mov    bx,PZ        ;place source origin in (bx)
  613.     mov    cx,[bx]        ;place length in cx
  614.     cmp    cx,0FFFFH    ;check for top of PDL flag
  615.     jnz    enlf1
  616.     call    RER        ;quit if PDL complement empty
  617. enlf1:    add    bx,cx        ;compute start of next compl. arg.
  618.     inc    bx
  619.     inc    bx
  620.     mov    PZ,bx        ;store new upper limit of PDL
  621.     ret
  622.  
  623. ;    (|)  Concatinate the top arguments on the PDL.
  624.  
  625. CONC:    mov    si,PX
  626.     mov    cx,PY
  627.     sub    cx,si        ;get length of top argument
  628.     call    UCL        ;pop top argument, set up pntrs to next
  629.     mov    di,dx        ;new py is destination
  630.     cld
  631.     mov    ax,ds
  632.     mov    es,ax
  633.     repnz    movs    byte [di],[si]
  634.     mov    PY,di        ;record new terminal address
  635.     ret
  636.  
  637. ;    (p)  Put px and siz on the pushdown list.
  638.  
  639. GXS:    mov    dx,PX
  640.     mov    bx,PY
  641.     mov    cx,bx
  642.     sub    cx,dx        ;calculate length of top argument
  643.     push    cx        ;put length on 8080 stack
  644.     push    dx        ;put origin on 8080 stack
  645.     call    PUTW        ;put top of 8080 stack on REC PDL
  646.     call    PUTW        ;put the next item there too
  647.     ret            ;can't combine <call, ret> into <jmp>
  648.  
  649. ;    (c) Reserve a block on the pushdown list. <n,c> creates
  650. ;    a block of length n, and puts n-2 at the front of the
  651. ;    block as a size indicator.  Then, if n .ge. 2, it will
  652. ;    be there as a length indicator for a buffer. <=====maybe change this?
  653.  
  654. BLOK:    mov    bx,PX        ;pointer to argument
  655.     mov    cx,[bx]        ;fetch the argument
  656.     mov    [bx],cx        ;store header
  657.     sub    word ptr [bx],2
  658.     call    OARG        ;is there enough space to reuse arg?
  659.     mov    PY,bx        ;increment in (bx), it goes into py
  660.     push    PX        ;px has origin of block just formed
  661.     call    PUTW        ;record block origin as new argument
  662.     ret            ;can't replace <call putw, ret> by jmp
  663.  
  664. ;    (h) Save the state of the machine and leave the SP value on
  665. ;    the PDL, if arg is null; otherwise restore the state of the
  666. ;    machine from values at the stack pointed to by the address
  667. ;    on the PDL.
  668.  
  669. MST:    pop    rtaddr        ;put return address aside
  670.     pushf            ;Flags to the stack
  671.     push    ax        ;Accumulator to stack
  672.     push    bx        ;BX to stack
  673.     push    cx        ;CX to stack
  674.     push    dx        ;DX to stack
  675.     push    bp        ;Base pointer to stack
  676.     push    si        ;Source index to stack
  677.     push    di        ;Destination index to stack
  678.     push    ds        ;Data segment to stack
  679.     push    es        ;Extra segment to stack
  680.     mov    ax,PY        ;compute argument length
  681.     sub    ax,PX        ;and lift top
  682.     call    UCL        ;before pushing pointers
  683. ;    push    PX        ;PDL pointers
  684. ;    push    PY
  685. ;    push    PZ
  686. ;    push    P0        ;WS pointers
  687. ;    push    P1
  688. ;    push    P2
  689. ;    push    P3
  690. ;    push    P4
  691. ;    push    WSEG
  692.     test    ax,ax
  693.     jnz    mrst        ;restore if arg nonnull
  694.     mov    cx,4        ;need 4 bytes for SS and SP
  695.     call    NARG        ;A ROYAL MESS WILL ENSUE IF NARG FAILS
  696.     mov    [bx],ss        ;record stack segment value
  697.     mov    2[bx],sp    ;record stack pointer value
  698.     add    bx,cx        ;compute new PY
  699.     mov    PY,bx        ;and update it
  700.     jmps    mrst2
  701.  
  702. mrst:    xchg    bx,dx        ;get previous PY back in BX
  703.     cmp    al,2        ;see if top arg has size 2
  704.     jnz    mrst1
  705.     call    UCL        ;yes, clean up stack
  706.     xchg    dx,bx        ;get PY back into BX
  707.     mov    ss,2[bx]    ;restoring pointers should be below
  708.     mov    sp,4[bx]    ;the 2-byte argument
  709.     add    sp,20        ;get rid of stored stuff (10 regs)
  710. ;    add    sp,38        ;get rid of stored stuff (10 regs + 9 ptrs)
  711.     jmps    mrst2
  712.  
  713. mrst1:    mov    ss,2[bx]    ;fetch SS from the PDL
  714.     mov    sp,4[bx]    ;SP too, now it points to previous store
  715. ;    pop    WSEG        ;so we can pop everything
  716. ;    pop    P4        ;we pushed in reverse
  717. ;    pop    P3
  718. ;    pop    P2
  719. ;    pop    P1
  720. ;    pop    P0
  721. ;    pop    PZ
  722. ;    pop    PY
  723. ;    pop    PX
  724.     pop    es
  725.     pop    ds
  726.     pop    di
  727.     pop    si
  728.     pop    bp
  729.     pop    dx
  730.     pop    cx
  731.     pop    bx
  732.     pop    ax
  733.     popf
  734. mrst2:    push    rtaddr        ;restore return address
  735.     ret            ;and exit
  736.  
  737. ;    Load a single variable into (cx) from the pushdown
  738. ;    list.  No register is sure to be preserved.
  739.  
  740. CXLD:    mov    bx,PX        ;pointer to argument
  741.     mov    cx,[bx]        ;fetch low order byte
  742.     call    ESLD        ;get segment address
  743.     jmp    UCL        ;erase argument [(cx) is unchanged]
  744.  
  745. ;    Load register pair (dx) from the pushdown list.
  746. ;    (cx) will be preserved, (bx) not.
  747.  
  748. DXLD:    mov    bx,PX        ;pointer to argument
  749.     push    word ptr [bx]        ;fetch word
  750.     call    UCL        ;erase argument
  751.     pop    dx        ;restore (dx) since UCL modified it
  752.     ret
  753.  
  754. ;    (=)  Test the two top arguments on the pushdown list
  755. ;    for equality.  The arguments may be of any length, but
  756. ;    will be equal only when of the same length and composed
  757. ;    of the same sequence of bytes. The top argument will be
  758. ;    popped whatever the outcome, but when equality is true
  759. ;    both will be popped.
  760.  
  761. EQL:    mov    di,PX        ;under argument
  762.     mov    cx,PY
  763.     sub    cx,di        ;obtain length of top argument
  764.     call    UCL        ;lift top argument
  765.     mov    si,PX
  766.     mov    bx,PY
  767.     sub    bx,si
  768.     cmp    bx,cx        ;compare lengths
  769.     jnz    EQF
  770.     cld
  771.     mov    ax,ds
  772.     mov    es,ax
  773.     repz    cmps    byte [di],[si]
  774.     jnz    EQF
  775.     jmp    CUCL        ;both agree, erase second arg, TRUE
  776. EQF:    ret            ;disagree so FALSE
  777.  
  778. ;    Load (es) with (ds) if PDL argument length is 2 bytes
  779. ;    Load!(es) from upper two bytes if length is 4 bytes
  780.  
  781. ESLD:    mov    ax,PY
  782.     mov    bx,PX
  783.     sub    ax,bx
  784.     cmp    ax,2
  785.     jnz    esl1
  786.     mov    ax,ds        ;two-byte argument
  787.     mov    es,ax
  788.     ret
  789. esl1:    cmp    ax,4
  790.     jnz    esl2
  791.     mov    ax,2[bx]    ;four-byte argument
  792.     mov    es,ax
  793.     ret
  794. esl2:    call    RR1        ;error record with one lift
  795.  
  796. ;    -------------------------------------------------------
  797. ;
  798. ;    Some of the service routines which are likely to be
  799. ;    external references in other modules are:
  800. ;
  801. ;        puon    push one byte on PDL
  802. ;        putw    push address on PDL
  803. ;        thrl    load  three arguments onto 8080 stack
  804. ;        twol    load two arguments onto 8080 stack
  805. ;        onel    load one argument onto 8080 stack
  806. ;        bcld    load (cx) from PDL, pop PDL
  807. ;        deld    load (dx) from PDL, pop PDL
  808. ;
  809. ;    -------------------------------------------------------
  810.  
  811.     END
  812.  
  813.