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

  1.  
  2. ;    =======================================================
  3. ;
  4. ;    Module composed of workspace operators for REC/MARKOV.
  5. ;    These are specialized subroutines for manipulating a
  6. ;    "workspace,"  which is an array together with five
  7. ;    pointers.  The workspace will probably (but not always)
  8. ;    hold text, subdivisions of which are marked off by the
  9. ;    pointers.  They in turn are:
  10. ;
  11. ;        p0  the beginning of both space and text
  12. ;        p1  the beginning of a specific segment
  13. ;        p2  the end of a specific segment
  14. ;        p3  the end of the entire text
  15. ;        p4  the physical end of the available space
  16. ;
  17. ;    The uniform method to designate intervals is that the
  18. ;    beginning is inclusive, while the end is exclusive.  In
  19. ;    that way a null interval can be represented through two
  20. ;    equal pointers.  The workspace operators and predicates
  21. ;    move data around and compare it with the help of these
  22. ;    pointers.  Other operators move data between the work-
  23. ;    space and the pushdown list.
  24. ;
  25. ;    The complete list of operators and predicates is:
  26. ;
  27. ;        A    advance pointer 1 if possible
  28. ;        B    retract pointer 1 if possible
  29. ;        D    delete interval between p1 and p2
  30. ;        E    test equality between workspace and PDL
  31. ;        F    find a specified segment in the workspace
  32. ;        I    insert in the workspacve following p2
  33. ;        J    move p1 to beginning
  34. ;        M    test workspace for an interval
  35. ;        Q    move interval between p1 and p2 to PDL
  36. ;        U    find segment between delimiters
  37. ;        V    find segment including delimiters
  38. ;        Y   restore pointer 1 to previous value
  39. ;        Z    move p2 to end
  40. ;        a    extend interval from p1 if possible
  41. ;        b    extend interval to p2 if possiblle
  42. ;        e    extend limit of text if possible
  43. ;        f    fill if space is available
  44. ;        j    null interval at front of segment
  45. ;        q    place p1, p2-p1 on PDL
  46. ;        w    store (or possibly exchange) workspace header
  47. ;        z    null interval at end of segment
  48. ;        <    restrict workspace to segment p1-p2
  49. ;        >    open workspace to previous span
  50. ;
  51. ;    Version released during the Summer School, 1980.
  52. ;
  53. ;          MKV80 - Copyright (C) 1980
  54. ;        Universidad Autonoma de Puebla
  55. ;             All Rights Reserved
  56. ;
  57. ;         [Harold V. McIntosh, 28 August 1980]
  58. ;
  59. ;    May 20, 1983 - M modified to test interval membership
  60. ;    May 20, 1983 - h suppressed, ''w replaces it
  61. ;    =======================================================
  62.  
  63.  
  64. ;    Entry points to locations in RAM storage, which will be
  65. ;    found in the module FXT.
  66.  
  67.     ext    p0,p1,p2,p3,p4
  68.     ext    px,py,pz,pt
  69.  
  70. ;    Entry points to programs in the REC nucleus, which will
  71. ;    be found in the module REC.
  72.  
  73.     ext    ucl,cucl
  74.     ext    psiz,siz,narg,oarg
  75.     ext    sng,sing,skp,seq
  76.     ext    req,rer,rr2
  77.     ext    miuc,mduc
  78.  
  79. ;    Entry points in the module PDL.
  80.  
  81.     ext    onel,twol,thrl,bcld
  82.     ext    putw
  83.  
  84. ;    =======================================================
  85. ;    Further auxiliary subroutines pertinent to REC/MARKOV.
  86. ;    =======================================================
  87.  
  88. ;    Move by increment until source limit.
  89.  
  90. miul::    mov    a,c    ;compare low bytes
  91.     cmp    e    ;
  92.     jnz    mil    ;disagreement so continue
  93.     mov    a,b    ;compare high bytes
  94.     cmp    d    ;
  95.     rz        ;agreement so limit was reached
  96. mil:    ldax    d    ;fetch source
  97.     mov    m,a    ;store in destination
  98.     inx    d    ;advance source pointer
  99.     inx    h    ;advance destination pointer
  100.     jmp    miul    ;repeat
  101.  
  102. ;    Move by decrement until source limit.
  103.  
  104. mdul::    mov    a,c    ;compare low bytes
  105.     cmp    e    ;
  106.     jnz    mdl    ;disagreement so continue
  107.     mov    a,b    ;compare high bytes
  108.     cmp    d    ;
  109.     rz        ;limit was reached so we're through
  110. mdl:    dcx    d    ;retract source pointer
  111.     dcx    h    ;retract destination pointer
  112.     ldax    d    ;fetch source byte
  113.     mov    m,a    ;place in destination
  114.     jmp    mdul    ;repeat
  115.  
  116. ;    Compare by increment until limit.  On entry, (BC) holds
  117. ;    the limit, (DE) points to the principal chain, and (HL)
  118. ;    points to the secondary chain.  On exit, (BC) remains
  119. ;    unchanged, while (DE) and (HL) either point to where
  120. ;    the discrepancy occurred if the chains were not equal,
  121. ;    or the byte beyond the chains when they are equal.
  122. ;    This latter is the REC convention to indicate segments.
  123. ;    Return is to the calling sequence for a mismatch, or
  124. ;    through a three byte skip when the chains match, which
  125. ;    is also the REC convention.
  126.  
  127. ciul:    mov    a,c    ;get the low byte of the limit
  128.     cmp    e    ;compare to low byte of principal
  129.     jnz    cil    ;doesn't match so keep comparing
  130.     mov    a,b    ;now get high byte of limit
  131.     cmp    d    ;to compare to high byte of principal
  132.     jz    skp    ;limit reached so leave pointers, skip
  133. cil:    ldax    d    ;fetch byte in principal string
  134.     cmp    m    ;compare to byte in secondary string
  135.     rnz        ;no match: keep pointers, go right back
  136.     inx    d    ;advance principal
  137.     inx    h    ;advance secondary
  138.     jmp    ciul    ;ready for the next go around
  139.  
  140. ;    Search by increment until limit.  On entry, (BC) holds
  141. ;    a limit, (DE) the reference pointer which indicates the
  142. ;    byte to be found and which does not change, while (HL)
  143. ;    holds the variable pointer which steps along a chain.
  144. ;    On exit, (BC) and (DE) are unchanged, leaving (HL) to
  145. ;    point either to the matching byte [TRUE] or just beyond
  146. ;    the searched chain [FALSE]. According to the REC norms,
  147. ;    a TRUE result generates a skip, while a FALSE result
  148. ;    produces an immediate return to the calling point.
  149. ;    It would be more efficient to load the reference byte
  150. ;    rather than point to it, but this form serves as an
  151. ;    inner loop to a program which prefers to modify (DE).
  152.  
  153. siul:    mov    a,c    ;fetch low byte of limit
  154.     cmp    l    ;compare to low byte of pointer
  155.     jnz    sil    ;mismatch so limit can't have arrived
  156.     mov    a,b    ;high byte of limit
  157.     cmp    h    ;versus high byte of pointer
  158.     rz        ;equal: byte wasn't found, false
  159. sil:    ldax    d    ;load the reference byte
  160.     cmp    m    ;compare to the string
  161.     jz    skp    ;they match, leave the pointer, skip
  162.     inx    h    ;go on to next byte
  163.     jmp    siul    ;and repeat the cycle
  164.  
  165. ;    And by increment until count.  On entry, (BC) holds the
  166. ;    count, (DE) points to the beginning of an array which
  167. ;    will not be modified [source], and (HL)    points to the
  168. ;    beginning of an array which will be modified by ANDing
  169. ;    it bytewise with the first [destination].  On exit, the
  170. ;    count will be zero while the pointers will lie at the
  171. ;    ends of their ranges.
  172.  
  173. aiuc::    mov    a,c    ;fetch low byte of count
  174.     ora    b    ;superimpose high byte
  175.     rz        ;return when count reaches zero
  176.     ldax    d    ;fetch unchanging participant
  177.     ana    m    ;AND with the alterable participant
  178.     mov    m,a    ;store the result of the encounter
  179.     inx    h    ;increment ANDed pointer
  180.     inx    d    ;increment ANDing pointer
  181.     dcx    b    ;decrement count
  182.     jmp    aiuc    ;repeat cycle
  183.  
  184. ;    Or by increment until count.
  185.  
  186. oiuc::    mov    a,c    ;fetch low byte of count
  187.     ora    b    ;superimpose high byte
  188.     rz        ;quit whenever count is zero
  189.     ldax    d    ;fetch unchanging participant
  190.     ora    m    ;OR with the alterable participant
  191.     mov    m,a    ;store the result
  192.     inx    h    ;increment pointer to ORed byte
  193.     inx    d    ;increment pointer to ORing byte
  194.     dcx    b    ;decrement counter
  195.     jmp    oiuc    ;repeat cycle
  196.  
  197. ;    Exclusive Or by increment until count.
  198.  
  199. xiuc::    mov    a,c    ;fetch low byte of count
  200.     ora    b    ;superimpose high byte
  201.     rz        ;return when count reaches zero
  202.     ldax    d    ;fetch unchanging participant
  203.     xra    m    ;XOR with the alterable participant
  204.     mov    m,a    ;store the result
  205.     inx    h    ;increment pointer to XORed byte
  206.     inx    d    ;increment pointer to XORing byte
  207.     dcx    b    ;decrement counter
  208.     jmp    xiuc    ;repeat cycle
  209.  
  210. ;    Complement by increment until count.
  211.  
  212. kiuc::    mov    a,c    ;fetch low byte of count
  213.     ora    b    ;superimpose high byte
  214.     rz        ;return when count reaches zero
  215.     mov    a,m    ;fetch operand
  216.     cma        ;complement it
  217.     mov    m,a    ;return it to memory
  218.     inx    h    ;advance pointer to operand
  219.     dcx    b    ;diminish count
  220.     jmp    kiuc    ;repeat cycle
  221.  
  222. ;    =======================================================
  223. ;    Workspace subroutines for REC/MARKOV.
  224. ;    =======================================================
  225.  
  226. ;    (a)  Generate a segment of length n forward from p1 if
  227. ;    possible.  A predicate which, when FALSE, leaves the
  228. ;    deficit by which the segment could not be formed on the
  229. ;    pushdown list.
  230.  
  231. lca::    call    bcld    ;load n into (BC)
  232.     lhld    p3    ;p3 is the limit for the segment
  233.     xchg        ;place it in register (DE)
  234.     lhld    p1    ;we want to advance pointer 1
  235.     call    sing    ;skip if increment not greater
  236.     jmp    lcaf    ;insufficient space, calculate deficit
  237.     shld    p2    ;give p2 the incremented value
  238.     jmp    skp    ;return with the value TRUE
  239. lcaf:    mov    a,l    ;low byte of p1+n
  240.     sub    e    ;low byte of limit
  241.     mov    c,a    ;low byte of deficit
  242.     mov    a,h    ;high byte of p1+n
  243.     sbb    d    ;high byte of limit
  244.     mov    b,a    ;high byte of deficit
  245.     push    b    ;argument to putw must be on 8080 stack
  246.     call    putw    ;record deficit
  247.     ret        ;FALSE return: <jmp putw> won't do
  248.  
  249. ;    (A)  Pointer 1 advances by one byte, if possible.
  250.  
  251. uca::    lhld    p1    ;fetch pointer 1
  252.     inx    h    ;advance by 1
  253.     xchg        ;and set it aside
  254.     lhld    p3    ;fetch limit
  255.     mov    a,l    ;compare low bytes
  256.     sub    e    ;
  257.     mov    a,h    ;and then high bytes
  258.     sbb    d    ;
  259.     rc        ;forget it, return FALSE if past limit
  260.     lhld    p2    ;fetch pointer 2
  261.     xchg        ;and swap with pointer 1
  262.     shld    p1    ;we can safely store pointer 1
  263.     call    sng    ;but it still must not pass pointer 2
  264.     shld    p2    ;if it did, pointer 2 = pointer 1
  265.     jmp    skp    ;but in either event, return TRUE
  266.  
  267. ;    (b)  Generate a segment of length n backward from p2,
  268. ;    if possible.
  269.  
  270. lcb::    call    bcld    ;load top argument into (BC), erase it
  271.     lhld    p2    ;fetch pointer 2 into (HL)
  272.     mov    a,l    ;calculate low order byte of difference
  273.     sub    c    ;by subtracting the displacement
  274.     mov    e,a    ;and storing it in register E
  275.     mov    a,h    ;then high order byte of difference
  276.     sbb    b    ;which must consider a possible borrow
  277.     mov    d,a    ;and then goes into regisger D
  278.     lhld    p0    ;now get the beginning of the workspace
  279.     mov    a,e    ;get ready to compare to new p1
  280.     sub    l    ;first the low byte
  281.     mov    a,d    ;then the high byte
  282.     sbb    h    ;likewise requiring the carry bit
  283.     rc        ;low limit passed, abandon the attempt
  284.     xchg        ;otherwise move new p1 into (HL)
  285.     shld    p1    ;record it
  286.     jmp    skp    ;generate TRUE return for the predicate
  287.  
  288. ;    (B)  Pointer 1 retreats by one byte, if possible.
  289.  
  290. ucb::    lhld    p0    ;fetch left limit
  291.     xchg        ;place in registers (DE)
  292.     lhld    p1    ;fetch pointer
  293.     dcx    h    ;move backwards one byte
  294.     mov    a,l    ;compare low bytes for limit
  295.     sub    e    ;
  296.     mov    a,h    ;compare high bytes for limit
  297.     sbb    d    ;
  298.     rc        ;return false as NOP if passed
  299.     shld    p1    ;otherwise store new position
  300.     jmp    skp    ;and return with value TRUE
  301.  
  302. ;    Delete text between pointers 1 and 2.
  303.  
  304. ucd::    lhld    p2    ;fetch end of deleted text
  305.     xchg        ;put it in (DE)
  306.     lhld    p1    ;fetch beginning of deleted text
  307.     call    req    ;return if interval is null
  308.     shld    p2    ;after deletion, interval is null
  309.     lhld    p3    ;end of text
  310.     mov    c,l    ;place in (BC) as source limit
  311.     mov    b,h    ;
  312.     lhld    p1    ;beginning of interval is destination
  313.     call    miul    ;close interval by a block move
  314.     shld    p3    ;destination limit is new end of text
  315.     ret
  316.  
  317. ;    (e)  Attempt to move pointer 3 forward. If insufficient
  318. ;    space remains, this predicate is false and places the
  319. ;    amount of remaining space [p4-p3] on the pushdown list.
  320.  
  321. lce::    call    bcld    ;load argument into BC, pop it
  322.     lhld    p4    ;fetch p4, which is physical limit
  323.     xchg        ;move it to register (DE)
  324.     lhld    p3    ;end of text, which we want to extend
  325.     call    sing    ;skip if increment not greater
  326.     jmp    lcef    ;insufficient space: calculate balance
  327.     xchg        ;put extended value of p3 aside
  328.     lhld    p3    ;fetch the previous end of text
  329.     shld    p1    ;make it the beginning of new interval
  330.     xchg        ;now we are ready to use the new p3
  331.     shld    p2    ;p1-p2 comprises the whole extension
  332.     shld    p3    ;record the extended value of p3
  333.     jmp    skp    ;TRUE return
  334. lcef:    lhld    p3    ;to calculate p4-p3 we need p3
  335.     mov    a,e    ;low byte of p4
  336.     sub    l    ;low byte of p3
  337.     mov    c,a    ;low byte of balance
  338.     mov    a,d    ;high byte of p4
  339.     sbb    h    ;high byte of p3
  340.     mov    b,a    ;high byte of balance
  341.     push    b    ;putw requires argument on 8080 stack
  342.     call    putw    ;insert balance on pushdown list
  343.     ret        ;TRUE return: <jmp putw> won't work
  344.  
  345. ;    (E) Check equality between the pushdown list and the
  346. ;    workspace.  The top argument will be erased whatever
  347. ;    the outcome of the test, a characteristic common to
  348. ;    E, F, M, U, and V.  If there is a segment originating
  349. ;    at p1 which is equal to the argument, p2 will move to
  350. ;    delimit it, otherwise p2 remains unchanged.
  351.  
  352. uce::    lhld    py    ;end of top argument
  353.     mov    b,h    ;move it to (BC)
  354.     mov    c,l    ;
  355.     lhld    px    ;beginning of top argument
  356.     xchg        ;move it to (DE)
  357.     lhld    p1    ;beginning of workspace segment in (HL)
  358.     call    ciul    ;subroutine making actual comparison
  359.     jmp    ucl    ;comparison failed, lift argument, quit
  360.     xchg        ;end of matching segment to (DE)
  361.     lhld    p3    ;end of valid text
  362.     mov    a,l    ;see whether we've run over
  363.     sub    e    ;compare low bytes
  364.     mov    a,h    ;
  365.     sbb    d    ;compare high bytes
  366.     jc    ucl    ;failed by running over
  367.     xchg        ;put end of segment in (HL)
  368.     shld    p2    ;it becomes the new p2
  369.     jmp    cucl    ;erase argument anyway, skip for TRUE
  370.  
  371. ;    (f)  Fill. <'XXX' f> will replace the text following
  372. ;    pointer 1 by XXX if pointer 2 does not conflict,
  373. ;    whereupon pointers 1 and 2 delimit what remains of
  374. ;    the interval they originally encompassed, making this
  375. ;    predicate TRUE.  Otherwise it will be FALSE, with the
  376. ;    pointers unaltered.  When f fails, its argument is
  377. ;    erased, otherwise the insert is conserved for repeated
  378. ;    use in a block fill.  f is true even if its argument
  379. ;    completely fills the available space, since it reports
  380. ;    whether or not an insertion took place rather than
  381. ;    whether any space remains.
  382.  
  383. lcf::    call    psiz    ;determine length of insert
  384.     lhld    p2    ;load p2
  385.     xchg        ;place it in register (DE)
  386.     lhld    p1    ;now load p1
  387.     dad    b    ;add the length of the insert to it
  388.     mov    a,e    ;compare this to p2
  389.     sub    l    ;begin with the low byte
  390.     mov    a,d    ;then compare high bytes
  391.     sbb    h    ;
  392.     jc    ucl    ;insert too big, FALSE and erase insert
  393.     lhld    px    ;get insert origin
  394.     xchg        ;place it in register (DE)
  395.     lhld    p1    ;load destination origin
  396.     call    miuc    ;call block move until count
  397.     shld    p1    ;final destination location is new p1
  398.     jmp    skp    ;keep insert, generate TRUE return
  399.  
  400. ;    (F)  Search for text.  The text in the workspace is
  401. ;    examined from left to right beginning at pointer 1 to
  402. ;    see if the object of comparison on the pushdown list
  403. ;    can be found.  If so, its replica in the workspace is
  404. ;    bracketed by pointers 1 and 2, while the model itself
  405. ;    is discarded.  Even if no replica is found, the model
  406. ;    is still discarded, but then the value is FALSE and the
  407. ;    pointers 1 and 2 retain their original sites.  Should
  408. ;    several replicas exist, only the first is taken; if
  409. ;    consecutive searches for the same object are made, the
  410. ;    same replica will be found repeatedly.  This permits
  411. ;    nested fragments of the same object to be found on
  412. ;    successive searches, but requires an intermediate
  413. ;    collapse of the interval p1-p2 in favor of p2 [say by
  414. ;    using ''I] to scan multiple occurrences of the same
  415. ;    object.
  416.  
  417. ucf::    lhld    px    ;beginning of object of search
  418.     xchg        ;place pointer in (DE)
  419.     lhld    py    ;end of object of search into (HL)
  420.     call    seq    ;skip if equal
  421.     jmp    uf1    ;continuation if object is non-null
  422.     lhld    p1    ;beginning of null workspace interval
  423.     shld    p2    ;record it as end of a null interval
  424.     jmp    cucl    ;pop argument, TRUE return
  425. uf1:    lhld    p3    ;fetch address of end of text
  426.     mov    b,h    ;move it to (BC)
  427.     mov    c,l    ;
  428.     lhld    p1    ;load origin of search
  429. uf2:    call    siul    ;search by increment until limit
  430.     jmp    ucl    ;pop argument, FALSE return
  431.     shld    pt    ;location where first characters match
  432.     push    b    ;save limit
  433.     lhld    py    ;limit of search object
  434.     mov    b,h    ;place it in (BC)
  435.     mov    c,l    ;
  436.     lhld    pt    ;comparison origin
  437.     call    ciul    ;compare by increment until limit
  438.     jmp    uf3    ;comparison failed
  439.     pop    b    ;end of text = search limit
  440.     mov    a,c    ;compare to end of matching text
  441.     sub    l    ;
  442.     mov    a,b    ;
  443.     sbb    h    ;
  444.     jc    ucl    ;matching text ran over, so FALSE
  445.     shld    p2    ;mark end of matching text
  446.     lhld    pt    ;fetch beginning of matching text
  447.     shld    p1    ;mark beginning of interval
  448.     jmp    cucl    ;pop argument, TRUE return
  449. uf3:    pop    b    ;recover search limit
  450.     lhld    px    ;front of search object again
  451.     xchg        ;(DE) points to comparison character
  452.     lhld    pt    ;point of last first-character match
  453.     inx    h    ;move past it
  454.     jmp    uf2    ;continue the search
  455.  
  456. ;    (I)  Insert text following pointer 2; upon completion
  457. ;    pointers bracket inserted material.  If the proposed
  458. ;    insertion will not fit, an error indicator is generated
  459. ;    and the attempt is abandoned.  An F followed by an I
  460. ;    will insert material after the found text, but if an
  461. ;    intermediate ''F is given, insertion will be made at
  462. ;    the front of the text.  A ''I may be used to form null
  463. ;    intervals, if they are desired at the end of a segment.
  464.  
  465. uci::    lhld    p2    ;point where insertion will be made
  466.     shld    p1    ;pointer 1 to precede inserted material
  467.     push    h    ;keep destination end for future use
  468.     lhld    px    ;source origin
  469.     xchg        ;place it in (DE)
  470.     lhld    py    ;source end
  471.     call    siz    ;calculate size of insert
  472.     xthl        ;save source end
  473.     push    h    ;but keep it under destination end
  474.     lhld    p4    ;end pf physical space
  475.     xchg        ;place it in register (DE)
  476.     lhld    p3    ;end of present text
  477.     call    sing    ;skip if increment not greater
  478.     call    rr2    ;no space, pop PDL twice
  479.     xchg        ;destination origin into (DE)
  480.     lhld    p3    ;source origin into (HL)
  481.     xchg        ;exchange these two registers
  482.     shld    p3    ;destination origin is new end of text
  483.     pop    b    ;destination limit into (BC)
  484.     call    mdul    ;move by decrement until source limit
  485.     shld    p2    ;source limit is end of insert
  486.     pop    b    ;source limit into (BC)
  487.     lhld    px    ;source origin into (HL)
  488.     xchg        ;really ought to be in (DE)
  489.     lhld    p1    ;new p1 is destination origin, in (HL)
  490.     call    miul    ;move by increment until source limit
  491.     jmp    ucl    ;I removes its argument upon completion
  492.  
  493. ;    (j)  Null interval at p1.  Equivalent to ''F or ''E.
  494.  
  495. lcj::    lhld    p1    ;pointer to beginning of interval
  496.     shld    p2    ;make end of interval the same
  497.     ret
  498.  
  499. ;    (J) Back to beginning of workspace.  Extends whatsoever
  500. ;     interval back to the beginning of the entire text.
  501.  
  502. ucj::    lhld    p0    ;fetch pointer to beginning of text
  503.     shld    p1    ;make it the beginning of the interval
  504.     ret
  505.  
  506. ;    (M)  Test whether a segment of the workspace lies in the
  507. ;    interval defined by the pushdown list, inclusive of its
  508. ;    endpoints. <a,b,M> is TRUE if there is a segment x starting
  509. ;    at p1, such that a .LE. x .LE. b, FALSE otherwise. According
  510. ;    to the common style of E, F, I, M, U, and V, the arguments
  511. ;    are erased whatever might be the outcome of the comparison.  
  512. ;    Likewise, FALSE results in no workspace pointer changes.
  513. ;    <'',b,M> will trivially succeed with '' in the workspace,
  514. ;    but <a,'',M> will be interpreted by ignoring b, then
  515. ;    looking for a workspace segment equal to or greater than a.
  516.  
  517. ucm::    lhld    px    ;calculate <org, siz> for the
  518.     xchg        ; top argument, b. They have
  519.     lhld    py    ; to be saved so that a can be
  520.     mov    a,l    ; tested first.
  521.     sub    e    ;
  522.     mov    l,a    ;
  523.     mov    a,h    ;
  524.     sbb    d    ;
  525.     mov    h,a    ;
  526.     push    h    ;HL = siz(b)
  527.     push    d    ;DE = org(b)
  528.     call    UCL    ;discard b
  529.     lhld    px    ;pointer to argument a
  530.     xchg        ;place it in DE
  531.     lhld    p1    ;pointer to workspace under comparison
  532.     mov    b,h    ;place it in BC as tentative p2
  533.     mov    c,l    ;
  534. um1:    lhld    py    ;pointer to end of argument a
  535.     call    seq    ;skip if null argument - eg px=py
  536.     jmp    um7    ;non-trivial comparison to be made
  537.  
  538. ;    We get to um2 if the comparison of argument a was
  539. ;    completed successfully, so we have to go back and
  540. ;    puck up argument b, then compare it too.
  541.  
  542. um2:    mov    h,b    ;move BC over to HL
  543.     mov    l,c    ;
  544.     pop    d    ;org(b)
  545.     pop    b    ;siz(b)
  546.     mov    a,c    ;siz = 0 means TRUE
  547.     ora    b    ;
  548.     jz    um4    ;record endpoint, quit
  549.     push    h    ;save p2
  550.     lhld    p1    ;run through interval again
  551. um3:    ldax    d    ;
  552.     cmp    m    ;
  553.     jc    um6    ;wrong inequality, so FALSE
  554.     inx    h    ;
  555.     inx    d    ;
  556.     dcx    b    ;
  557.     mov    a,c    ;
  558.     ora    b    ;
  559.     jnz    um3    ;
  560.     pop    h    ;recover the saved p2
  561. um4:    shld    p2    ;it can be stored as end pointer
  562.     jmp    cucl    ;TRUE return
  563. um5:    pop    h    ;
  564. um6:    pop    h    ;
  565.     jmp    UCL    ;FALSE return
  566. um7:    lhld    p3    ;fetch end of text
  567.     mov    a,h    ;compare it with end of interval
  568.     cmp    b    ;compare high bytes
  569.     jnz    um8    ;whole addresses can't be equal
  570.     mov    a,l    ;compare low bytes
  571.     cmp    c    ;
  572.     jz    um5    ;end of text without success - FALSE
  573. um8:    xchg        ;pointer to argument back in (HL)
  574.     ldax    b    ;fetch byte from workspace
  575.     inx    b    ;advance pointer automatically
  576.     cmp    m    ;compare to argument
  577.     jc    um5    ;fail if argument is bigger
  578.     jnz    um2    ;byte comparison decided, check limits
  579.     xchg        ;bytes were equal, keep trying
  580.     inx    d    ;advance argument pointer
  581.     jmp    um1    ;repeat cycle
  582.  
  583. ;    (q)  Put p1, p2-p1 on PDL.
  584.  
  585. lcq::    lhld    p1    ;fetch p1
  586.     xchg        ;put it aside
  587.     lhld    p2    ;fetch p2
  588.     call    siz    ;leaves (HL)-(DE) in (BC)
  589.     push    b    ;stash p2-p1 on 8080's PDL
  590.     push    d    ;and then p1 on top of that
  591.     call    putw    ;one argument from top of 8080 stack
  592.     call    putw    ;then another so we've got both
  593.     ret        ;cannot use jmp putw for call putw, ret
  594.  
  595. ;    (Q)  Copy workspace to pushdown.  The interval between
  596. ;    p1 and p2 is placed on the pushdown list.
  597.  
  598. ucq::    lhld    p1    ;fetch beginning of interval
  599.     xchg        ;place in (DE)
  600.     lhld    p2    ;fetch end of interval
  601.     call    siz    ;length of interval into (BC)
  602.     call    narg    ;close old arg, check space, def new
  603.     lhld    p1    ;fetch source origin
  604.     xchg        ;place it in register (DE)
  605.     lhld    px    ;fetch destination origin for (HL)
  606.     call    miuc    ;move by increment until count
  607.     shld    py    ;destination end is argument end
  608.     ret
  609.  
  610. ;    (w)  Exchange workspace header. There are three forms of
  611. ;    this operator which are available: the argument may be
  612. ;    null, indicating that the header block goes onto the PDL,
  613. ;    either a single block of ten bytes, or else the pair
  614. ;    <org, siz>.  The distinction is implicit, according to
  615. ;    whether the top argument has two bytes or ten bytes.
  616. ;    The first case arises from a previous usage of h (or
  617. ;    perhaps deliberate construction), while the second is
  618. ;    more likely in the initial allocation of a workspace. A
  619. ;    single block is erased after use, while it is supposed
  620. ;    that a previous definition existed when the pair form
  621. ;    is used.  In such a case, the old block of bytes would
  622. ;    be substituted for the two arguments in case it needed
  623. ;    to be restored later.  When a workspace is generated
  624. ;    from its specifications, pointers 1 and 2 as well as 3
  625. ;    are set to encompass the entire space. Many other forms
  626. ;    can be arranged by a subsequent use of j, D, and so on.
  627.  
  628. lcw::    call    psiz    ;determine size of argument
  629.     mov    a,c    ;check whether it is null
  630.     ora    b    ;
  631.     jnz    lw2    ;
  632. lw1:    lxi    b,10    ;10 bytes required from PDL
  633.     call    narg    ;verify space, new px into (HL)
  634.     lxi    d,p0    ;source is pointer block
  635.     call    miuc    ;block movement
  636.     shld    py    ;final destination is arg end
  637.     ret
  638. lw2:    lxi    h,-10    ;ten for comparison
  639.     dad    b    ;subtract it from size
  640.     mov    a,l    ;check low byte for zero
  641.     ora    h    ;but the high byte can be mixed in
  642.     jnz    lww    ;if length not 10, suppose it was 2
  643.     lhld    px    ;fetch pointer to argument
  644.     xchg        ;place in (DE) as source origin
  645.     lxi    h,p0    ;p0 is destination origin
  646.     call    miuc    ;move by increment until count (10)
  647.     jmp    ucl    ;erase the argument
  648. lww:    lhld    px    ;create p0...p4 from org,siz
  649.     call    twol    ;trnsfr two args from PDL to 8080 stack
  650.     call    lw1    ;place existing header on PDL
  651.     pop    h    ;recover under arg, namely org
  652.     pop    b    ;recover upper arg, namely siz
  653.     shld    p0    ;origin of workspace
  654.     shld    p1    ;segment at front of workspace
  655.     dad    b    ;add size
  656.     shld    p2    ;segment traverses whole workspace
  657.     shld    p3    ;which defines end of occupied text
  658.     shld    p4    ;as well as physical end
  659.     ret
  660.  
  661. ;    (U)  Search for interval, excluding limits.  The object
  662. ;    of the search is defined by its delimiters: thus if the
  663. ;    text YYY is to be found, it must be specified as the
  664. ;    one sandwiched between XXX and ZZZ.  Then by executing
  665. ;    'XXX'F followed by 'ZZZ'U pointers 1 and 2 will bracket
  666. ;    YYY.  U erases its argument, whether TRUE or FALSE, by
  667. ;    a custom common to all search or comparison predicates.
  668. ;    By the same custom, pointers 1 and 2 remain unmoved if
  669. ;    the search fails. ''U generates a null interval at the
  670. ;    end of the last interval that was created.
  671.  
  672. ucu::    lhld    p1    ;fetch beginning of last interval
  673.     push    h    ;save for possible restoration
  674.     lhld    p2    ;fetch end of last interval
  675.     push    h    ;save for future use
  676.     shld    p1    ;search begins at end of p1-p2 interval
  677.     call    ucf    ;use the search subroutine
  678.     jmp    uuu    ;search failed
  679.     lhld    p1    ;beginning of found interval
  680.     shld    p2    ;is end of result interval
  681.     pop    h    ;recover end of last interval
  682.     shld    p1    ;it is beginning of U-interval
  683.     pop    h    ;discard beginning of last interval
  684.     jmp    skp    ;TRUE return from predicate
  685. uuu:    pop    h    ;discard end of last interval-it's same
  686.     pop    h    ;recover beginning of last interval
  687.     shld    p1    ;restore it
  688.     ret        ;FALSE return from predicate
  689.  
  690. ;    (V)  Search for interval, including limits.  This
  691. ;    predicate is similar to U, the difference being that
  692. ;    after a successful search, p1 and p2 bracket both the
  693. ;    delimiters as well as the text which they define,
  694. ;    whereas U merely brackets the intervening text.
  695.  
  696. ucv::    lhld    p1    ;pointer to beginning of last interval
  697.     push    h    ;save it until later
  698.     lhld    p2    ;pointer to end of last interval
  699.     shld    p1    ;which is starting point for new search
  700.     call    ucf    ;predicate F always makes the search
  701.     jmp    uvv    ;search failed, F was FALSE
  702.     pop    h    ;recover the old p1
  703.     shld    p1    ;which still applies to V
  704.     jmp    skp    ;TRUE return with old p1, new p2
  705. uvv:    pop    h    ;recover original p1
  706.     shld    p1    ;and restore it
  707.     ret        ;FALSE return with p1 and p2 unchanged
  708.  
  709. ;    (Y)  Recover pointer 1.  There are those times when it
  710. ;    is desirable to note a spot in the workspace, through
  711. ;    qL for example, and then be able to return to it later
  712. ;    on.  However intervening deletions, insertions or even
  713. ;    workspace openings and closings may have rendered it
  714. ;    invalid so a check is made to ensure the preservation
  715. ;    of the relative order of p0, p1, and p3. We may only
  716. ;    want to restore p1, or alternatively both p1 and p2.
  717. ;    A distinction between the cases is made by the size of
  718. ;    the argument: <qL ... Y> will give a two-byte argument
  719. ;    and restore p1; while <q| ... Y> will yield a four-byte
  720. ;    argument and restore both p1 and p2. Y is a predicate,
  721. ;    in the first case always TRUE with p1 and p2 accomodated
  722. ;    as best can be. In the second case, failure to accomodate
  723. ;    makes Y FALSE.
  724.  
  725. ucy::    call    psiz    ;BC = py-px
  726.     lxi    h,-4    ;
  727.     dad    b    ;
  728.     mov    a,l    ;
  729.     ora    h    ;
  730.     jz    uyi    ;siz=4 means p1,p2-p1 concatinated
  731.     lhld    px    ;pointer to top argument
  732.     mov    e,m    ;fetch low byte of pointer
  733.     inx    h    ;pass to high byte
  734.     mov    d,m    ;DE contains the old pointer
  735.     lhld    p0    ;fetch beginning of text
  736.     mov    a,e    ;check that p1 will be greater or equal
  737.     sub    l    ;
  738.     mov    a,d    ;
  739.     sbb    h    ;
  740.     jc    uyy    ;if less, store p0 instead
  741.     lhld    p3    ;fetch end of text
  742.     mov    a,l    ;check that p1 will be less or equal
  743.     sub    e    ;
  744.     mov    a,h    ;
  745.     sbb    d    ;
  746.     jc    uyn    ;if not, make p2 = p1 = p3
  747.     lhld    p2    ;fetch p2
  748.     xchg        ;p1 and p2 in more favorable registers
  749.     mov    a,e    ;check that p1 less or equal to p2
  750.     sub    l    ;
  751.     mov    a,d    ;
  752.     sbb    h    ;
  753.     jnc    uyy    ;if so, just record p1
  754. uyn:    shld    p2    ;record null interval between p1 and p2
  755. uyy:    shld    p1    ;give p1 whatever value it'll have
  756.     jmp    cucl    ;pop the argument
  757.  
  758. ;    A four-byte argument means we have concatinated <org, siz>
  759. ;    and that both p1 and p2 are to be restored.
  760.  
  761. uyi:    mov    c,m    ;BC = old p1
  762.     inx    h    ;
  763.     mov    b,m    ;
  764.     inx    h    ;
  765.     mov    a,c    ;DE = old p2 [p1+(p2-p1)]
  766.     add    m    ;
  767.     mov    e,a    ;
  768.     inx    h    ;
  769.     mov    a,b    ;
  770.     adc    m    ;
  771.     mov    d,a    ;
  772.     lhld    p0    ;check that p1 is not less than p0
  773.     mov    a,e    ;
  774.     sub    l    ;
  775.     mov    a,d    ;
  776.     sbb    h    ;
  777.     jc    ucl    ;no - so take FALSE return
  778.     lhld    p3    ;check that p1 is not beyond p3
  779.     mov    a,l    ;
  780.     sub    e    ;
  781.     mov    a,h    ;
  782.     sbb    d    ;
  783.     jc    ucl    ;no - so take false return
  784.     mov    l,c    ;all clear, so restore them
  785.     mov    h,b    ;
  786.     shld    p1    ;
  787.     xchg        ;
  788.     shld    p2    ;
  789.     jmp    cucl    ;TRUE return
  790.  
  791. ;    (z)  Null interval at end of segment.  Equivalent to
  792. ;    ''I, ''U, or 0b.
  793.  
  794. lcz::    lhld    p2    ;pointer to end of interval
  795.     shld    p1    ;make beginning of interval the same
  796.     ret
  797.  
  798. ;    (Z)  Move p2 to the end of the workspace, thereby
  799. ;    extending whatever interval on to the end of the text.
  800.  
  801. ucz::    lhld    p3    ;pointer to the end of text
  802.     shld    p2    ;make end of interval the same
  803.     ret
  804.  
  805. ;    (<)  Close down workspace. The workspace is confined to
  806. ;    the interval between pointers 1 and 2.  The reason for
  807. ;    this could be to restrict the editing operations to a
  808. ;    smaller range, or it could be to have absolute freedom
  809. ;    to work over some material before incorporating it into
  810. ;    the main text.  As a practical matter, the text between
  811. ;    pointers 2 and 3 is displaced to the far end of the
  812. ;    workspace and the original values of pointers 0 and 4
  813. ;    are recorded before setting up the new values of the
  814. ;    pointers. Subsequent insertions and deletions then have
  815. ;    much less material to move.
  816.  
  817. bra::    lxi    b,4    ;need 4 bytes from wkspace for pointers
  818.     lhld    p4    ;fetch physical end of workspace
  819.     xchg        ;place it in (DE)
  820.     lhld    p3    ;fetch end of text
  821.     call    sing    ;skip if increment not greater
  822.     call    rer    ;error if no space left in workspace
  823.     lhld    p2    ;pointer to source limit
  824.     mov    b,h    ;move it to (BC)
  825.     mov    c,l    ;
  826.     lhld    p3    ;pointer to source origin
  827.     xchg        ;move it to (DE)
  828.     lhld    p4    ;pointer to destination origin
  829.     call    mdul    ;move by decrement until limit
  830.     xchg        ;place destination limit in (DE)
  831.     lhld    p4    ;fetch old value of physical end
  832.     mov    a,h    ;store at ws end in front of seg p2-p3
  833.     dcx    d    ;
  834.     stax    d    ;store high byte
  835.     mov    a,l    ;
  836.     dcx    d    ;
  837.     stax    d    ;store low byte
  838.     lhld    p0    ;fetch old value of physical beginning
  839.     mov    a,h    ;store at ws end in front of old p4
  840.     dcx    d    ;
  841.     stax    d    ;store high byte
  842.     mov    a,l    ;
  843.     dcx    d    ;
  844.     stax    d    ;store low byte
  845.     xchg        ;put new physical end in (HL)
  846.     shld    p4    ;record it in p4
  847.     mov    l,c    ;move p2 into (HL)
  848.     mov    h,b    ;
  849.     shld    p3    ;store it as new end of text
  850.     lhld    p1    ;move p1 into (HL)
  851.     shld    p0    ;store it as new beginning of text
  852.     ret        ;p2 remains at end of newlymade text
  853.  
  854. ;    (>)  Open up the workspace.  This is the complementary
  855. ;    operator to <, which is used to return the scope of the
  856. ;    pointers p0 and p4 to their original range.  The text
  857. ;    forming the restricted workspace is incorporated in its
  858. ;    entirity in place of the material originally lying in
  859. ;    the interval p1-p2.  An error condition can arise from
  860. ;    opening a workspace that was never closed, but it will
  861. ;    be anulled if a zero address was placed at the pointer
  862. ;    4 during initialization of the workspace.
  863.  
  864. ket::    lhld    p4    ;load the end of the universe
  865.     mov    e,m    ;load the old p0 into (DE)
  866.     inx    h    ;
  867.     mov    d,m    ;
  868.     mov    a,e    ;zero means opening too many times
  869.     ora    d    ;
  870.     cz    rer    ;so note error and abandon attempt
  871.     inx    h    ;go on to fetch old p4 into (BC)
  872.     mov    c,m    ;
  873.     inx    h    ;
  874.     mov    b,m    ;
  875.     inx    h    ;pointer always one ahead
  876.     xchg        ;place old p0 in (HL)
  877.     shld    p0    ;to facilitate returning it to p0
  878.     lhld    p3    ;end of txt is dest to replace old tail
  879.     call    miul    ;move by increment until limit
  880.     shld    p3    ;destination end is new end of text
  881.     xchg        ;origin end is new end of universe
  882.     shld    p4    ;which must be duly recorded
  883.     ret
  884.  
  885. ;    -------------------------------------------------------
  886. ;
  887. ;    Some of the block action subroutines which might be
  888. ;    found as external references in the other modules:
  889. ;
  890. ;        miul    move by increment until source limit
  891. ;        mdul    move by decrement until source limit
  892. ;        aiuc    and by increment until count
  893. ;        oiuc    or by increment until count
  894. ;        xiuc    xor by increment until count
  895. ;        kiuc    complement by increment until count
  896. ;
  897. ;    -------------------------------------------------------
  898.  
  899.     end
  900.