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