home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MISC / REC.ZIP / REC86A.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-02-04  |  31.1 KB  |  1,036 lines

  1. ;    *******************************************************
  2. ;    *  REC module containing the REC nucleus and some of  *
  3. ;    *  the really indispensable operators and predicates  *
  4. ;    *  such as those defining two byte binary numbers and *
  5. ;    *  ASCII constant strings.  The model of a pushdown   *
  6. ;    *  list is assumed in the expectation that additional *
  7. ;    *  operators and predicates will also follow reversed *
  8. ;    *  Polish notation. There are additionally many small *
  9. ;    *  service routines which may be used externally.     *
  10. ;    *                              *
  11. ;    *  REC86 was obtained from the previously existing    *
  12. ;    *  REC80 by applying SORCIM's TRANS86 translator and  *
  13. ;    *  then adjusting the resulting code manually. It is  *
  14. ;    *  intended that REC86 will be functionally identical *
  15. ;    *  to REC80. All error corrections, additions, or     *
  16. ;    *  alterations are made simultaneously to the two     *
  17. ;    *  programs, when they are not purely cosmetic.          *
  18. ;    *  Braces, creating a different style of subroutine   *
  19. ;    *  definition, were incorporated in REC at the time   *
  20. ;    *  the translation to the Intel 8086 was made.          *
  21. ;    *                              *
  22. ;    *  This version supports separate code, data (base    *
  23. ;    *  page, pointers and PDL), extra (WS) and stack      *
  24. ;    *  segments. [G. Cisneros, Feb 1984]              *
  25. ;    *                              *
  26. ;    *  REC86 contains the following compiling entries:    *
  27. ;    *                              *
  28. ;    *    reclp    left parenthesis              *
  29. ;    *    recco    colon                      *
  30. ;    *    recsc    semicolon                  *
  31. ;    *    recrp    right parenthesis              *
  32. ;    *    recop    operator                  *
  33. ;    *    recpr    predicate                  *
  34. ;    *    recsq    single quotes                  *
  35. ;    *    recdq    double quotes                  *
  36. ;    *    reccm    comments                  *
  37. ;    *    reco1    operator with one ASCII parameter     *
  38. ;    *    recp1    predicate with one ASCII parameter    *
  39. ;    *    recms    unary minus sign              *
  40. ;    *    recdd    decimal digit                  *
  41. ;    *    recol    operator, with lookahead          *
  42. ;    *    recpl    predicate, with lookahead          *
  43. ;    *                              *
  44. ;    *  REC86 contains the following operators and          *
  45. ;    *  predicates:                          *
  46. ;    *                              *
  47. ;    *    '    single quote                  *
  48. ;    *    "    double quote                  *
  49. ;    *    nu    two byte decimal number              *
  50. ;    *    O    decimal ASCII string to number          *
  51. ;    *    #    number to decimal ASCII string          *
  52. ;    *    L    erase argument (lift)              *
  53. ;    *    @    execute subroutine              *
  54. ;    *    {    initiate program segment          *
  55. ;    *    }    discontinue program segment          *
  56. ;    *    ?    report detected error              *
  57. ;    *                              *
  58. ;    *  The following are initialization programs which    *
  59. ;    *  can be called at the outset of a compilation.      *
  60. ;    *                              *
  61. ;    *    inre    initialize REC temporary registers    *
  62. ;    *                              *
  63. ;    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  64. ;    *                              *
  65. ;    *    REC86  -  Copyright (C) 1982, 1984          *
  66. ;    *      Universidad Autonoma de Puebla          *
  67. ;    *        All Rights Reserved              *
  68. ;    *                              *
  69. ;    *    [Harold V. McIntosh, 25 April 1982]          *
  70. ;    *    [Gerardo Cisneros, 8 February 1984]          *
  71. ;    *                              *
  72. ;    14 April 1983 - AR recognizes @@              *
  73. ;    14 April 1983 - cosmetic changes: use of <lea>          *
  74. ;    14 April 1983 - suppress TLU and TLV              *
  75. ;    14 January 1984 - 4 explicit jmps's for sorcim.cnv    *
  76. ;    8 February 1984 - Individual segments              *
  77. ;    3 July 1984 - @@ takes 1- and 2-byte arguments from   *
  78. ;    the PDL; compilation of combinations included - GCS   *
  79. ;    15 Aug 1984 - E.P.s for nL, LL and &L - GCS          *
  80. ;    29 June 1985 - word-size @ table for x - GCS          *
  81. ;    *******************************************************
  82.  
  83. ;    =======================================================
  84. ;    The nucleus of REC is a compiler for control symbols,
  85. ;    operators and predicates, some auxiliary subroutines,
  86. ;    and an initilazation routine.
  87. ;
  88. ;    The compiler proper uses only the folowing external
  89. ;    references:
  90. ;
  91. ;        RAM storage        xpd, ypd, zpd
  92. ;        I-O routine        read
  93. ;        skip instruction    skp
  94. ;
  95. ;    The RAM storage must be initialized, which may be
  96. ;    accomplished by calling inre.
  97. ;
  98. ;    The location in which the object code is placed is
  99. ;    passed along through the register pair (dx), which is
  100. ;    continually updated to reflect the next available byte.
  101. ;    None of the other registers are either conserved nor
  102. ;    significant after the completion of compilation.
  103. ;
  104. ;    The usage of the registers is the following
  105. ;
  106. ;        pair (cx) contains the execution pointer
  107. ;        pair (dx) contains the object program counter
  108. ;        pair (bx) contains the compiling address
  109. ;
  110. ;    =======================================================
  111.  
  112. ;    Equivalences defining INTEL 8086 instructions and some
  113. ;    constants.
  114.  
  115. CA    equ    0E8H        ;call w/16 bit displacement
  116. JU    equ    0E9H        ;jump w/16 bit displacement
  117. RN    equ    0C3H        ;return w/o change of segment
  118. POBX    equ    05BH        ;pop bx
  119. PUBX    equ    053H        ;push bx
  120. JUBX    equ    0E3FFH        ;jmp bx
  121. PUME    equ    036FFH        ;push direct address
  122. POME    equ    0068FH        ;pop into memory
  123. INBX    equ    043H        ;inc bx
  124. LDME    equ    006C7H        ;ld mem,imm
  125.  
  126. ;    Compile a left parenthesis.
  127.  
  128. RECLP:    pop    bp
  129.     push    ZPD        ;save the linkage to semicolon exits
  130.     push    YPD        ;save the higher linkage to false jumps
  131.     push    XPD        ;save the repeat references
  132.     mov    ax,0        ;initialze the new chains
  133.     mov    ZPD,ax        ;null TRUE exit list
  134.     mov    YPD,ax        ;null FALSE jump list
  135.     mov    XPD,dx        ;new parenthesis level begins here
  136.     jmp    bp
  137.  
  138. ;    Compile a colon.
  139.  
  140. RECCO:    mov    bx,XPD        ;pick up reference to left parenthesis
  141.     sub    bx,dx
  142.     lea    bx,-3[bx]
  143.     call    RECJU        ;and insert a jump to its location
  144.     jmp    RECFY        ;fill in any FALSE predicate jumps
  145.  
  146. ;    Compile a semicolon.
  147.  
  148. RECSC:    mov    bx,ZPD        ;pick up link to TRUE exit chain
  149.     call    RECJU        ;insert this one on it too
  150.     mov    ZPD,bx        ;store it as the new head of the chain
  151.     jmp    RECFY        ;fill in any FALSE predicate jumpe
  152.  
  153. ;    Compile an operator.
  154.  
  155. RECOP:    xchg    bx,dx
  156.     mov    cs:byte ptr [bx],CA    ;store the 8086 code for a call
  157.     lea    bx,3[bx]    ;advance (dx) to receive next byte
  158.     sub    cx,bx
  159.     mov    cs:(-2)[bx],cx
  160.     xchg    bx,dx
  161.     ret
  162.  
  163. ;    Compile a predicate.
  164.  
  165. RECPR:    call    RECOP        ;call its subroutine, same as operator
  166. RECYJ:    mov    bx,YPD        ;linkage to FALSE exits
  167.     call    RECJU        ;incorporate a jump if result FALSE
  168.     mov    YPD,bx        ;update for new head of chain
  169.     ret
  170.  
  171. ;    Compile a right parenthesis.
  172.  
  173. RECRP:    pop    bp        ;recover xpd, which is hidden
  174.     pop    XPD        ;replace it
  175.     cmp    XPD,0
  176.     jz    RECFP        ;if so, continue with recfp
  177.     pop    bx        ;recover wpd
  178.     call    RECJU        ;link expr to ypd on its own level
  179.     push    bx        ;but save pointer until we finish up
  180.     call    RECFY        ;false predicates in last segment
  181.     pop    YPD        ;replace ypd for higher level
  182.     mov    bx,ZPD        ;now we have destination for semicolons
  183.     call    recfc        ;so insert all the correct addresses
  184.     pop    ZPD        ;replace old zpd
  185.     jmp    bp
  186.  
  187. ;    Final right parentheses get a different treatment.
  188.  
  189. RECFP:    mov    bx,dx        ;compile pointer in bx
  190.     mov    cs:byte ptr [bx],RN    ;store a <ret> for false exit
  191.     inc    bx        ;ready for next byte
  192.     push    bx        ;save compile pointer
  193.     mov    dx,(offset SKP)        ;address of skip - TRUE exit from REC
  194.     call    RECFY        ;use it for last segment
  195.     mov    bx,ZPD        ;destination of semicolons now known
  196.     call    recfc        ;so fill out that chain
  197.     pop    dx        ;compile pointer that was saved
  198.     pop    YPD        ;restore old ypd
  199.     pop    ZPD        ;restore old zpd
  200.     ret            ;return one level higher than expected
  201.  
  202. ;    Insert a new element in a chain of jmp's which will
  203. ;    eventually have destination addresses.  In the interim
  204. ;    each is given the address of its predecessor. On entry
  205. ;    (dx) holds the address where the instruction will be
  206. ;    stored and (bx) holds the address of its predecessor.
  207. ;    On exit, (dx) is incremented by 3 to point to the next
  208. ;    free byte, and (bx) has the starting value of (dx).
  209.  
  210. RECJU:    xchg    bx,dx        ;(bx) and (dx) exchanged is better
  211.     mov    cs:byte ptr [bx],JU    ;store the jump instruction
  212.     inc    bx
  213.     mov    cs:[bx],dx        ;store old link
  214.     lea    dx,2[bx]
  215.     ret
  216.  
  217. ;    When the destination of a linked chain of jumps is
  218. ;    finally known, the destination can be substituted into
  219. ;    each one of the links.  On entry, (bx) contains the
  220. ;    address of the first link unless it is zero signifying
  221. ;    a null chain.
  222.  
  223. recfc:    or    bx,bx        ;test for end of chain
  224.     jz    recfx        ;if address is zero, chain ends
  225.     mov    ax,dx
  226.     dec    ax
  227.     dec    ax
  228. recfi:    mov    cx,cs:[bx]        ;save next link
  229.     mov    cs:[bx],ax        ;store destination
  230.     sub    cs:[bx],bx
  231.     mov    bx,cx        ;update link
  232.     or    bx,bx
  233.     jnz    recfi        ;continue
  234. recfx:    ret
  235.  
  236. ;    Call recfc with the intention of filling the y chain.
  237.  
  238. RECFY:    mov    bx,YPD
  239.     call    recfc
  240.     mov    YPD,bx
  241.     ret
  242.  
  243. ;    Subroutine which will initialize the temporary
  244. ;    registers used by the REC compiler.
  245.  
  246. INRE:    mov    bx,0
  247.     mov    XPD,bx
  248.     mov    YPD,bx
  249.     mov    ZPD,bx
  250.     ret
  251.  
  252.  
  253. ;    =======================================================
  254. ;    The following are specialized compiling subroutines
  255. ;    which apply to special structures and depend on the
  256. ;    model of a pushdown list with a linked chain structure
  257. ;    and special registers px and py delimiting the top
  258. ;    segment on the chain.
  259. ;    =======================================================
  260.  
  261. ;    -------------------------------------------------------
  262. ;    Compilation of quoted expressions.  Single and double
  263. ;    quotes may alternate with one another to an arbitrary
  264. ;    depth.  Both kinds of quotes are executed in the same
  265. ;    way, by loading the quoted expression from the program
  266. ;    onto the pushdown list.
  267. ;    -------------------------------------------------------
  268.  
  269. ;    Compile single quotes.
  270.  
  271. RECSQ:    call    RECOP        ;record call to qu
  272.     inc    dx        ;set aside two bytes
  273.     inc    dx        ;to hold length of ASCII chain
  274.     push    dx        ;keep beginning for future reference
  275.     push    cs:QUEN        ;delay cleanup until ret
  276. SQ:    call    word ptr read        ;read the next character
  277.     cmp    al,''''    ;test for single quote
  278.     jz    SQ2        ;if so go after entire chain
  279.     cmp    al,'"'        ;test for double quotes
  280.     jnz    SQ1
  281.     call    DQ1        ;if so, read it all
  282. SQ1:    xchg    bx,dx
  283.     mov    cs:[bx],al
  284.     xchg    bx,dx        ;otherwise keep on storing
  285.     inc    dx        ;and advancing pointer
  286.     jmp    SQ        ;go after next character
  287. SQ2:    ret
  288.  
  289. ;    Compile double quotes.
  290.  
  291. RECDQ:    call    RECOP        ;record call to qu
  292.     inc    dx        ;set aside two bytes
  293.     inc    dx        ;to hold length of chain
  294.     push    dx        ;put chain origin away for reference
  295.     push    cs:QUEN        ;delay cleanup until ret
  296. DQ0:    call    word ptr read        ;read the next character
  297.     cmp    al,'"'        ;test for double quotes
  298.     jz    DQ2        ;if so, chain finished
  299.     cmp    al,''''    ;check for single quotes
  300.     jnz    DQ1
  301.     call    SQ1        ;if so go after whole chain
  302. DQ1:    xchg    bx,dx
  303.     mov    cs:[bx],al
  304.     xchg    bx,dx        ;otherwise keep on storing
  305.     inc    dx        ;and advancing pointer
  306.     jmp    DQ0        ;go after next character
  307. DQ2:    ret
  308.  
  309. ;    Cleanup for both quote compilers.
  310.  
  311. QUEN    dw    ENQU        ;for the direct push
  312. ENQU:    pop    bx        ;beginning of chain in (bx)
  313.     mov    cx,dx
  314.     sub    cx,bx
  315.     mov    cs:(-2)[bx],cx    ;store length
  316.     ret
  317.  
  318. ;    (') (")    Execute single or double quote.
  319.  
  320. QU:    pop    bx        ;get call location off the 8080 stack
  321.     mov    cx,cs:[bx]        ;count
  322.     inc    bx        ;
  323.     inc    bx        ;
  324.     mov    si,bx        ;save source origin
  325.     add    bx,cx        ;calculate source end = return adress
  326.     push    bx
  327.     call    NARG        ;check space, put dest. pointer in (bx)
  328.     cld
  329.     mov    di,bx
  330.     mov    bp,ds
  331.     mov    es,bp
  332.     mov    ax,cs
  333.     mov    ds,ax
  334.     repnz    movsb
  335.     mov    ds,bp        ;restore (ds)
  336.     mov    PY,di        ;record end of argument
  337.     ret
  338.  
  339. ;    -------------------------------------------------------
  340. ;    Comments are enclosed in square brackets, which must be
  341. ;    balanced.  Code may be disabled by enclosing it in
  342. ;    square brackets, but care must be taken that the
  343. ;    expression so isolated does not contain individual
  344. ;    brackets, such as arguments of arrobas or quoted
  345. ;    brackets, which might disrupt the balance. Since
  346. ;    comments are ignored by the compiler they are not
  347. ;    executed.
  348. ;    -------------------------------------------------------
  349.  
  350. ;    Compile comments by ignoring them.
  351.  
  352. RECCM:    call    word ptr read        ;get next character
  353.     cmp    al,']'        ;test for closing ]
  354.     jz    RECCX        ;if so we're done
  355.     cmp    al,'['        ;test for beginning of new level
  356.     jnz    RECCM        ;otherwise keep on reading
  357.     call    RECCM        ;if so go after it recursively
  358.     jmp    RECCM
  359. RECCX:    ret
  360.  
  361. ;    -------------------------------------------------------
  362. ;    Sometimes, notably in compiling arroba as a call to a
  363. ;    subroutine named by a single letter, a parameter will
  364. ;    follow a subroutine call as its calling sequence.
  365. ;    -------------------------------------------------------
  366.  
  367. ;    Operator with one ASCII parameter.
  368.  
  369. RECO1:    call    RECOP        ;always compile the subroutine call
  370.     call    word ptr read        ;read the parameter
  371.     mov    bx,dx
  372.     mov    cs:[bx],al        ;store as a 1-byte calling sequence
  373.     inc    dx        ;always ready for next byte
  374.     ret
  375.  
  376. ;    Predicate with one ASCII parameter.
  377.  
  378. RECP1:    call    RECO1        ;compile as the analogous operator
  379.     jmp    RECYJ        ;then take account of false exit
  380.  
  381. ;    Predicate, with lookahead, to compile often-used
  382. ;    combinations like Ez and ED
  383.  
  384. RECPL:    call    RECOL        ;compile as the analogous operator
  385.     jmp    short pl0    ;short jump because recol may skip
  386.     call    RECYJ        ;call to link into chain
  387.     jmp    skp86        ;skip, we have the next character
  388. pl0:    jmp    RECYJ        ;no skip, just link into chain
  389.  
  390. ;    Operator, with lookahead, to compile often-used
  391. ;    combinations like pG and TL into a single call.
  392.  
  393. RECOL:    mov    bl,al        ;save first character
  394. ol1:    call    word ptr read    ;get the next valid character
  395.     call    svc86
  396.     jmp    short ol1
  397.     add    al,' '        ;restore to ASCII
  398.     push    ax        ;save, in case combination not found
  399.     push    cx        ;save exec addr of first letter
  400.     push    dx        ;as well as the compilation ptr
  401.     mov    bh,al        ;both letters in BX
  402.     mov    dx,CMT        ;combination table address
  403.     xchg    bx,dx        ;switch letters and address
  404. ol2:    mov    cx,[bx]        ;get next combination
  405.     jcxz    ol4        ;end of table, exit loop
  406.     cmp    cx,dx        ;else compare letters
  407.     jz    ol3        ;exit loop if found
  408.     add    bx,4        ;advance pointer to table
  409.     jmp    short ol2        ;try next
  410.  
  411. ol3:    pop    dx        ;found, get comp. ptr.
  412.     pop    cx        ;get rid of old exec addr
  413.     mov    cx,2[bx]    ;get exec. addr. of combination
  414.     pop    ax        ;get rid of saved character
  415.     jmp    RECOP        ;off to compile call
  416.  
  417. ol4:    pop    dx        ;not found, fetch comp. ptr.
  418.     pop    cx        ;and exec. addr. of first letter
  419.     call    RECOP        ;compile that
  420.     pop    ax        ;retrieve the second character
  421.     jmp    skp86        ;and skip, since no read necessary
  422.  
  423. ;    -------------------------------------------------------
  424. ;    Decimal numbers are of such frequent occurrence in the
  425. ;    form of counters, arguments, or just data that it is
  426. ;    convenient to compile them on sight without requiring
  427. ;    any special delimiters.  Likewise, negative numbers are
  428. ;    easier to designate using a minus sign than using their
  429. ;    modular form, but this should not prevent the use of a
  430. ;    minus sign as an operator.
  431. ;    -------------------------------------------------------
  432.  
  433. ;    Compile a minus sign. This involves determining whether
  434. ;    it is followed immediately by a decimal digit, in which
  435. ;    case it is compiled as part of a negative number.
  436.  
  437. RECMS:    call    word ptr read        ;read in one byte
  438.     call    MS1        ;decide whether it is a digit
  439.     push    ax        ;it was not, save it
  440.     call    RECOP        ;compile call to binary minus
  441.     pop    ax        ;recover the extra character
  442.     jmp    skp86        ;skip because we have next character
  443.  
  444. MS1:    call    RND        ;return if not digit
  445.     inc    sp        ;erase call to ms1
  446.     inc    sp        ;
  447.     call    RECDS        ;read and convert digit string
  448.     mov    cx,cs:GNU    ;fake that it was nu, not ms
  449.     push    ax        ;save terminating character
  450.     neg    bx        ;negate (bx)
  451.     jmp    DD1        ;continue as though positive number
  452.  
  453. GNU    dw    NU
  454.  
  455. ;    Compile a decimal digit, which requires reading any
  456. ;    further digits which follow, and saving the terminator.
  457.  
  458. RECDD:    push    cx        ;save execution address
  459.     call    RECDS        ;read and transform rest of digits
  460.     pop    cx        ;recover execution address
  461.     push    ax        ;recover terminating character
  462. DD1:    call    RECOP        ;compile subroutine call
  463.     xchg    bx,dx        ;(dx) and (bx) must be interchanged
  464.     mov    cs:[bx],dx        ;put word in calling sequence
  465.     inc    bx        ;
  466.     inc    bx        ;ready for next byte
  467.     xchg    bx,dx        ;put (dx) and (bx) back as they were
  468.     pop    ax        ;recover terminating character
  469.     jmp    skp86        ;skip over character read call
  470.  
  471. ;    Multiply (bx) by 10 and add A.  (dx) is conserved.
  472.  
  473. TXP:    mov    cx,bx        ;transfer (bx) to (cx)
  474.     add    bx,bx        ;multiply (bx) by 2
  475.     add    bx,bx        ;another 2 makes 4
  476.     add    bx,cx        ;the original (bx) makes 5
  477.     add    bx,bx        ;another 2 makes 10
  478.     add    bx,ax        ;add in the accumulator
  479.     ret
  480.  
  481. ;    The heart of number compilation.
  482.  
  483. RECDS:    and    al,0FH        ;mask ASCII down to binary value
  484.     mov    BL,al        ;put it into register pair (bx)
  485.     mov    BH,0        ;fill out H with a zero
  486. RD1:    call    word ptr read        ;read the next character
  487.     call    RND        ;quit if it is not another digit
  488.     call    TXP        ;multiply (bx) by ten and add A
  489.     jmp    RD1        ;continuing while digits keep coming
  490.  
  491. ;    Execute a number, which means load it on pdl.
  492.  
  493. NU:    mov    cx,2        ;two bytes will be required
  494.     call    NARG        ;close last argument, open new
  495.     pop    dx        ;get beginning of calling sequence
  496.     xchg    bx,dx
  497.     mov    ax,cs:[bx]    ;fetch number from code segment
  498.     xchg    bx,dx
  499.     mov    [bx],ax        ;and copy it over
  500.     inc    dx        ;on to the high order byte
  501.     inc    bx        ;and the place to store it
  502.     inc    dx        ;move on to program continuation
  503.     inc    bx        ;always leave PDL ready for next byte
  504.     push    dx        ;put back the return address
  505.     mov    PY,bx        ;mark end of the argument
  506.     ret
  507.  
  508. ;    (O) Transform an ASCII character string on the PDL into
  509. ;    a two-byte number.  Predicate - false if the argument
  510. ;    is not a digit string or null, leaving the argument
  511. ;    unchanged.
  512.  
  513. UCO:    mov    cx,2        ;two bytes are required
  514.     call    OARG        ;check that they are available
  515.     mov    bx,PY        ;fetch the end of the argument string
  516.     mov    byte ptr [bx],0    ;put a zero there to mark its end
  517.     mov    dx,PX        ;load pointer to argument string
  518.     mov    bx,0        ;zero in (bx) to start the conversion
  519. O1:    xchg    bx,dx
  520.     mov    al,[bx]
  521.     xchg    bx,dx        ;fetch one character
  522.     inc    dx        ;get ready for next
  523.     or    al,al        ;test for zero
  524.     jz    O2        ;go to accumulation phase
  525.     call    RND        ;FALSE, chain unaltered if non-digit
  526.     call    TXP        ;otherwise continue to work up value
  527.     jmp    O1        ;and keep on reading bytes
  528. O2:    xchg    bx,dx        ;safeguard converted number in (dx)
  529.     mov    bx,PX        ;get pointer to argument
  530.     mov    [bx],dx        ;store low byte
  531.     inc    bx        ;increment pointer
  532.     inc    bx        ;increment pointer again
  533.     mov    PY,bx        ;store to close argument
  534.     jmp    SKP        ;TRUE exit from predicate
  535.  
  536. ;    (#)  Change two-byte binary number into a decimal-based
  537. ;    ASCII string without sign. The special cases of a zero-
  538. ;    byte or a one-byte argument are also considered.
  539.  
  540. NS:    mov    cx,05H        ;five bytes may be required
  541.     call    OARG        ;reuse the old argument
  542.     mov    cx,PY
  543.     mov    bx,PX
  544.     sub    cx,bx
  545.     mov    ax,0        ;put zero in (dx) for default
  546.     jcxz    NS1        ;load nothing
  547.     mov    al,[bx]        ;load low byte
  548.     dec    cx        ;test for one byte
  549.     jcxz    NS1        ;only byte and it's loaded
  550.     mov    ah,1[bx]    ;load high byte
  551. NS1:    mov    bp,bx        ;save pointer for ASCII string
  552.     mov    cl,'0'        ;prepare to write a zero
  553.     mov    bx,-10000    ;will there be 5 digits?
  554.     add    bx,ax        ;
  555.     jb    NS2        ;
  556.     mov    bx,-1000    ;will there be 4 digits?
  557.     add    bx,ax        ;
  558.     jb    NS3        ;
  559.     mov    bx,-100        ;will there be 3 digits?
  560.     add    bx,ax        ;
  561.     jb    NS4        ;
  562.     mov    bx,-10        ;will there be 2 digits?
  563.     add    bx,ax        ;
  564.     jb    NS5        ;
  565.     jmp    NS6        ;write one no matter what
  566. NS2:    mov    bx,10000    ;ten thousands digit
  567.     call    NSA        ;
  568. NS3:    mov    bx,1000        ;thousands digit
  569.     call    NSA        ;
  570. NS4:    mov    bx,100        ;hundreds digit
  571.     call    NSA        ;
  572. NS5:    mov    bx,10        ;tens digit
  573.     call    NSA        ;
  574. NS6:    add    cl,al        ;units digit
  575.     mov    ds:[bp],cl    ;store the digit
  576.     inc    bp        ;position pointer for next byte
  577.     mov    PY,bp        ;done, store it as terminator
  578.     ret
  579.  
  580. NSA:    mov    dx,0        ;clear extension for div
  581.     div    bx        ;div bx into axdx
  582.     add    cl,al        ;form ASCII digit
  583.     mov    ax,dx        ;put remainder in ax
  584.     mov    ds:[bp],cl    ;store new digit
  585.     inc    bp        ;advance pointer
  586.     mov    cl,'0'        ;load a fresh ASCII zero
  587.     ret
  588.  
  589. ;    =======================================================
  590. ;    Some simple procedures to compile REC expressions into
  591. ;    subroutines, deposit a reference to them in a symbol
  592. ;    table, and eventually to recover the space and erase
  593. ;    the symbol table reference.
  594. ;    =======================================================
  595.  
  596. ;    Table search. The table whose address is stored at fxt
  597. ;    is consulted for its pair of addresses at position 4*A.
  598. ;    Thus on entry, A holds the table index.  This table
  599. ;    alternates the address of a compiling subroutine with
  600. ;    the execution address of the same entry.  On exit, (cx)
  601. ;    holds the execution address, (dx) is preserved, and a
  602. ;    jump is made to the compiling address.
  603.  
  604. rects:    mov    ah,0
  605.     mov    bp,ax        ;save the character
  606.     add    ax,ax
  607.     add    ax,ax
  608.     mov    bx,FXT        ;load base address of table
  609.     add    bx,ax
  610.     mov    ax,bp        ;restore letter to AX
  611.     add    al,' '        ;but in original ASCII form
  612.     push    word ptr [bx]        ;put the first entry in (cx)
  613.     mov    cx,2[bx]    ;table pointer is going
  614.     ret            ;then off to the compilation
  615.  
  616. ;    Pick out left delimiters: (, {, or [.
  617.  
  618. left:    call    word ptr read
  619.     cmp    al,'('
  620.     jz    eft
  621.     cmp    al,'{'
  622.     jz    eft
  623.     cmp    al,'['
  624.     jnz    left
  625.     call    reccm
  626.     jmp    short left
  627. eft:    ret
  628.  
  629. ;    A main program to compile characters one by one as
  630. ;    they are read in from the console.  Note that the
  631. ;    compiling programs invoked by rects can generate skips
  632. ;    when they have already read the following character.
  633. ;    This occurs most notably when compiling digits. Also
  634. ;    note that svc86 normalizes characters when it accepts
  635. ;    them.
  636.  
  637. recre:    call    word ptr read        ;read a character from whereever
  638. recrr:    call    svc86        ;check for space, control character
  639.     jmp    short recre    ;not valid, go back for another
  640.     call    rects        ;look up in table and compile it
  641.     jmp    short recre    ;read another character and repeat
  642.     jmp    short recrr    ;repeat but next character already read
  643.  
  644. ;    A subroutine which will pass over comments, and wait
  645. ;    for an opening left parenthesis or brace before compiling
  646. ;    a REC expression.
  647.  
  648. EMCE:    call    UCL        ;entry here erases an argument from PDL
  649. EMCX:    call    left        ;get a character from whereever
  650.     mov    dx,C1
  651.     mov    bx,C1
  652.     mov    bp,sp
  653.     xchg    bx,[bp]
  654.     push    bx
  655.     call    recrr        ;compiling prgrm one char already read
  656.     cmp    dx,C2        ;compare with high limit
  657.     ja    emc0
  658.     cmp    dx,C0        ;compare with low limit
  659.     jb    emc0
  660.     mov    C1,dx
  661.     ret
  662. emc0:    mov    bx,'pC'        ;Type fatal error msg and quit
  663.     jmp    FERR
  664.  
  665. EMCU:    pop    dx
  666.     pop    bx
  667.     push    dx
  668.     push    bx
  669.     mov    dx,(offset EMCV)
  670.     push    dx
  671.     jmp    bx
  672. EMCV:    jmp    EMCW
  673.     pop    C1
  674.     jmp    skp86
  675. EMCW:    pop    C1
  676.     ret
  677.  
  678. ;    ({) Introduce a series of definitions.
  679.  
  680. LBR:    xchg    bx,dx
  681.     mov    cs:byte ptr [bx],CA    ;insert a call to the executable subroutine
  682.     xchg    bx,dx
  683.     inc    dx
  684.     mov    cx,dx        ;place to put call address - keep in BC
  685.     inc    dx        ;make room
  686.     inc    dx
  687.     call    RECYJ        ;link in the FALSE exit
  688.     call    RECJU
  689.     push    bx        ;keep this address
  690.     push    XPD
  691.     mov    XPD,0        ;this is top level for ensuing subroutines
  692.     mov    bx,0
  693. LB1:    push    dx        ;record entry point to subroutine
  694.     inc    bx        ;increment count of subroutines
  695.     push    bx        ;keep it next to top on stack
  696.     push    cx        ;jump address at entry - keep it on top
  697.     call    left
  698.     call    recrr        ;compile at least one subroutine
  699. LB2:    call    word ptr read        ;get possible name of subroutine
  700.     cmp    al,'}'        ;no name - we execute this one
  701.     jz    LB3
  702.     call    svc86        ;convert name into serial number
  703.     jmp    short LB2    ;punctuation instead of name
  704.     add    al,' '
  705.     mov    ah,0
  706.     mov    bx,VRT
  707.     add    ax,ax
  708.     add    bx,ax
  709. ;    add    bx,ax        ;word-size entries
  710.     pop    cx        ;get this out of the way
  711.     mov    bp,sp
  712.     xchg    bx,[bp]        ;store table address, put subr count in bx
  713.     jmp    LB1
  714. LB3:    cld
  715.     mov    ax,cs
  716.     mov    es,ax
  717.     pop    bx        ;origin of brace compilation
  718.     mov    di,dx
  719.     lea    ax,2[bx]
  720.     sub    ax,di
  721.     neg    ax
  722.     mov    cs:[bx],ax
  723.     pop    cx        ;number of subroutines + 1
  724.     push    cx        ;we'll need it again later
  725.     mov    bp,cx        ;put it in bp too
  726.     dec    bp
  727.     add    bp,bp
  728.     add    bp,bp
  729.     add    bp,sp
  730.     mov    al,POBX
  731.     stosb
  732.     jmp    LB5
  733. LB4:    mov    ax,PUME    ;for each defined symbol we insert the
  734.     stosw
  735.     mov    ax,[bp]
  736.     stosw
  737.     mov    ax,LDME    ;
  738.     stosw
  739.     mov    ax,[bp]
  740.     stosw
  741.     mov    ax,2[bp]
  742.     stosw
  743.     sub    bp,4        ;we read the stack backwards
  744. LB5:    loop    LB4
  745.     mov    al,PUBX
  746.     stosb
  747.     mov    al,CA
  748.     stosb
  749.     pop    cx
  750.     pop    ax
  751.     sub    ax,di
  752.     dec    ax
  753.     dec    ax
  754.     stosw
  755.     push    cx
  756.     mov    al,JU        ;    jmp    $+6
  757.     stosb
  758.     push    di        ;    inx    h
  759.     inc    di        ;    inx    h
  760.     inc    di        ;    inx    h
  761.     mov    al,POBX
  762.     stosb
  763.     mov    al,INBX
  764.     stosb
  765.     stosb
  766.     stosb
  767.     mov    al,PUBX
  768.     stosb
  769.     pop    bx
  770.     lea    ax,2[bx]
  771.     sub    ax,di
  772.     neg    ax
  773.     mov    cs:[bx],ax
  774.     mov    al,POBX
  775.     stosb
  776.     pop    cx
  777.     jmp    LB7
  778. LB6:    mov    ax,POME        ;after an expression in braces is
  779.     stosw
  780.     pop    ax
  781.     stosw
  782.     inc    sp
  783.     inc    sp
  784. LB7:    loop    LB6
  785.     mov    ax,JUBX        ;the whole thing is finished off by a return
  786.     stosw
  787.     mov    dx,di
  788.     pop    cx
  789.     mov    XPD,cx
  790.     pop    bx
  791.     jcxz    LB8
  792.     lea    ax,2[bx]
  793.     sub    ax,dx
  794.     neg    ax
  795.     mov    cs:[bx],ax
  796.     ret
  797. LB8:    mov    cx,cs:[bx]
  798.     mov    ax,(offset SKP)-2    ;top level true return
  799.     sub    ax,bx
  800.     mov    cs:[bx],ax
  801.     mov    cs:byte ptr (-4)[bx],RN    ;top level false return
  802.     inc    sp        ;return one level higher than expected
  803.     inc    sp
  804.     ret
  805.  
  806. ;    (@) Subroutine which will transform an ASCII character
  807. ;    into a table reference, and then jump to the address
  808. ;    so encountered.  This is essentially REC's subroutine
  809. ;    call mechanism, necessarily a predicate since it calls
  810. ;    a REC expression, which is itself a predicate.
  811.  
  812. AR:    pop    bx        ;entry if name is a parameter
  813.     mov    al,cs:[bx]    ;read the calling sequence
  814.     inc    bx        ;advance pointer for return
  815.     push    bx        ;put it back on 8080 stack
  816.     cmp    al,'@'
  817.     jnz    XAR
  818.     mov    bx,PX        ;argument on PDL, compute size
  819.     mov    ax,[bx]        ;but fetch two bytes anyway
  820.     mov    cx,PY
  821.     sub    cx,bx
  822.     call    UCL        ;lift it before going on
  823.     cmp    cx,2        ;is it an address?
  824.     jnz    XAR        ;no, assume a letter
  825.     jmp    ax        ;yes, jump to it
  826.  
  827. XAR:    mov    ah,0        ;clear the high byte
  828.     add    ax,ax        ;compute address of table entry
  829. ;    add    ax,ax        ;word-size entries
  830.     mov    di,ax
  831.     mov    bx,VRT        ;entry when index is in register A
  832.     jmp    word ptr [bx+di]    ;then use it as jump address
  833.  
  834. ;    =======================================================
  835. ;    Some general service routines.
  836. ;    =======================================================
  837.  
  838. ;    Skip on valid character, meaning, not control symbol.
  839. ;    If valid, 20H (space) is subtracted, making A = 1, etc.
  840.  
  841. svc86:    cmp    al,'!'        ;reject space, excl is lower limit
  842.     jb    sv
  843.     cmp    al,7FH        ;seven bits is upper limit
  844.     jnb    sv
  845.     sub    al,' '        ;normalize to begin with (excl) = 1
  846.     pop    bp
  847.     inc    bp
  848.     inc    bp
  849.     jmp    bp
  850. sv:    ret            ;don't skip for control or flag bit
  851.  
  852. ;    Return if not decimal. A unchanged if not decimal, else
  853. ;    reduced to binary.
  854.  
  855. RND:    cmp    al,':'        ;colon follows 9 in ASCII alphabet
  856.     jnb    RTN
  857.     cmp    al,'0'        ;ASCII zero is lower limit
  858.     jb    RTN
  859.     sub    al,'0'        ;normalize to get binary values
  860.     mov    ah,0        ;zero for uncomplicated arithmetic
  861.     ret
  862. RTN:    inc    sp
  863.     inc    sp
  864.     ret
  865.  
  866. ;    Second level return on error.
  867.  
  868. RR2:    pop    bx        ;entry to clear two items from PDL
  869.     mov    bp,sp
  870.     xchg    bx,[bp]        ;
  871. RR1:    pop    bx        ;entry to clear one item from PDL
  872.     mov    bp,sp
  873.     xchg    bx,[bp]        ;
  874. RER:    pop    ax        ;site where ther error occurred
  875.     cmp    ER,0        ;only record the first error
  876.     jnz    RRR
  877.     mov    ER,ax
  878. RRR:    ret
  879.  
  880. ;    (?)  Test whether an error has been reported: predicate
  881. ;    which is true if er is nonzero, in which case it will
  882. ;    reset er.  It will also, if TRUE, place the calling
  883. ;    address of the last reported error on the pushdown
  884. ;    list.  If false, only a FALSE return is generated. Note
  885. ;    the ironic circumstance that, if PDL is exhausted, qm
  886. ;    can generate an error trying to report an error - but
  887. ;    the TRUE result will still be valid.
  888.  
  889. QM:    cmp    ER,0        ;test the error cell
  890.     jz    QQ        ;FALSE return if no error
  891.     mov    cx,2        ;we want two bytes for error address
  892.     call    NARG        ;check space, prepare for new argument
  893.     mov    ax,ER        ;fetch error address
  894.     mov    [bx],ax        ;transfer it to REC PDL
  895.     inc    bx        ;
  896.     inc    bx        ;pointer must always advance
  897.     mov    PY,bx        ;end of the argument
  898.     mov    ER,0        ;reset ER
  899.     jmp    SKP        ;TRUE return - there was an error
  900. QQ:    ret
  901.  
  902. ;    Generate a skip (skp), which is often combined with the
  903. ;    erasure of an argument on the pushdown list (cucl).
  904.  
  905. CUCL:    call    UCL        ;erase the top argument
  906. SKP:    pop    bp
  907.     add    bp,3        ;assume the skip will be over a
  908.     jmp    bp        ;three-byte instruction, such as a jump
  909.  
  910. skp86:    pop    bp
  911.     inc    bp
  912.     inc    bp
  913.     jmp    bp
  914.  
  915. ;    Test PDL space beginning at top argument. On entry (cx)
  916. ;    contains the total space required.  On exit, (cx) stays
  917. ;    unchanged, (dx) holds pz, while (bx) holds px+(cx).
  918. ;    If the space is not available, return is made from the
  919. ;    calling program after noting the error.  Otherwise
  920. ;    normal return to the calling program occurs. The likely
  921. ;    use of oarg is to record a result without having to go
  922. ;    through ucl, NARG.
  923.  
  924. OARG:    mov    dx,PZ        ;load limit of PDL
  925.     dec    dx        ;keep one byte margin
  926.     mov    bx,PX        ;load beginning of current argument
  927.     add    bx,cx
  928.     jc    NRER        ;Error if PX+(cx) wraps around 64K
  929.     sub    dx,bx
  930.     jb    NRER        ;No space, take nearby NRER exit
  931.     ret            ;yes, continue normally
  932.  
  933. ;    Check space for, and then set up, a new argument. On
  934. ;    entry, (cx) should contain the amount of additional
  935. ;    space required.  The program will automatically add
  936. ;    two more bytes for the pointer which would close the
  937. ;    argument and then, if the required space is available,
  938. ;    close it, define the new px, and leave its value in
  939. ;    (bx).  (dx) will contain the old value of px to be used
  940. ;    in case the superseded argument is still interesting.
  941. ;    When space is not available, the error return rer is
  942. ;    taken.
  943. ;
  944. ;    The entry RARG can be taken when it is known that
  945. ;    sufficient space is available but the pointers still
  946. ;    have to be set up.
  947.  
  948. NARG:    mov    di,cx
  949.     mov    bx,PY        ;load end of current argument
  950.     lea    ax,3[bx+di]
  951.     cmp    ax,PZ
  952.     jnb    NRER        ;check available space
  953.     cmp    ax,PX
  954.     jb    NRER        ;Error if (ax) wrapped around 64K
  955. RARG:    mov    dx,PX        ;entry if no space check needed
  956.     mov    bx,PY
  957.     mov    [bx],dx        ;low byte of closing link
  958.     inc    bx        ;on to high byte
  959.     inc    bx        ;beginning of new space
  960.     mov    PX,bx        ;which is recorded by px
  961.     ret            ;and remains in (bx)
  962. NRER:    mov    bx,'DP'        ;quit on PDL overflow
  963.     jmp    FERR
  964.  
  965. ;    (&L)  A commonly used combination, erasing only the lower arg.
  966.  
  967. XLFT:    mov    si,PX
  968.     mov    cx,PY        ;pointers to top
  969.     sub    cx,si
  970.     call    UCL        ;"lift" it
  971.     test    dx,dx        ;empty PDL?
  972.     jz    xlre
  973.     call    UCL        ;lift the lower one
  974.     call    RARG        ;close the next
  975.     mov    di,bx        ;new px to di
  976.     cld
  977.     mov    ax,ds
  978.     mov    es,ax
  979.     repnz    movsb        ;move down the old top
  980.     mov    PY,di        ;record new end
  981. xlre:    ret
  982.  
  983. ;    (L)  Remove argument from pushdown list. There are no
  984. ;    requirements for entry to ucl.  On exit, (cx) remains
  985. ;    unchanged, (dx) holds the end of the former argument
  986. ;    and (bx) holds the beginning of the former argument -
  987. ;    the one that was exposed when the current argument was
  988. ;    erased. Erasing non-existent arguments creates an error
  989. ;    condition which is noted and ignored.
  990.  
  991. LFTW:    call    UCL        ;entry point for LL
  992.  
  993. UCL:    mov    bx,PX        ;pointer to current argument
  994.     dec    bx        ;just behind the present
  995.     dec    bx
  996.     mov    dx,[bx]        ;argument is the address
  997.     or    dx,dx        ;so we always test out of caution
  998.     jz    ULE
  999.     mov    PY,bx        ;(bx) now holds end of previous arg.
  1000.     mov    PX,dx        ;pointer to beginning of prev. arg.
  1001.     xchg    bx,dx
  1002.     ret
  1003. ULE:    inc    bx        ;restore bx
  1004.     inc    bx
  1005.     call    RER        ;record error if pointer was zero
  1006.  
  1007. ;    Null program for undefined operators.
  1008.  
  1009. NOOP:    ret
  1010.  
  1011. ;    =======================================================
  1012. ;
  1013. ;    Some of the service routines, which might be external
  1014. ;    references in other modules, are:
  1015. ;
  1016. ;        oarg    space when reusing an argument
  1017. ;        NARG    close old argument, space for new
  1018. ;        rarg    same as NARG when space is assured
  1019. ;        skp    generic skip
  1020. ;        rer    return on error
  1021. ;        rr2    rer after popping two addresses
  1022. ;        rtn    generic return
  1023. ;        ucl    lift argument from PDL (L)
  1024. ;        cucl    lift argument, then skip
  1025. ;
  1026. ;    Three entry points can be used according to the variant
  1027. ;    of the compiling operator C desired.  One of them could
  1028. ;    also be used by a main program.
  1029. ;
  1030. ;        emce    lift pushdown, open block, compile
  1031. ;        emcx    compile a sequence of subroutines
  1032. ;
  1033. ;    =======================================================
  1034.  
  1035. ;    END
  1036.