home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MISC / REC.ZIP / REC86FA.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-02-04  |  26.9 KB  |  898 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. ;    *    L    erase argument (lift)              *
  51. ;    *    @    execute subroutine              *
  52. ;    *    {    initiate program segment          *
  53. ;    *    }    discontinue program segment          *
  54. ;    *    ?    report detected error              *
  55. ;    *                              *
  56. ;    *  The following are initialization programs which    *
  57. ;    *  can be called at the outset of a compilation.      *
  58. ;    *                              *
  59. ;    *    inre    initialize REC temporary registers    *
  60. ;    *                              *
  61. ;    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  62. ;    *                              *
  63. ;    *    REC86  -  Copyright (C) 1982, 1984          *
  64. ;    *      Universidad Autonoma de Puebla          *
  65. ;    *        All Rights Reserved              *
  66. ;    *                              *
  67. ;    *    [Harold V. McIntosh, 25 April 1982]          *
  68. ;    *    [Gerardo Cisneros, 8 February 1984]          *
  69. ;    *                              *
  70. ;    14 April 1983 - AR recognizes @@              *
  71. ;    14 April 1983 - cosmetic changes: use of <lea>          *
  72. ;    14 April 1983 - suppress TLU and TLV              *
  73. ;    14 January 1984 - 4 explicit jmps's for sorcim.cnv    *
  74. ;    8 February 1984 - Individual segments - GCS          *     
  75. ;    10 May 1984 - Floating point - GCS              *
  76. ;    3 July 1984 - @@ takes 1- and 2-byte arguments from   *
  77. ;    the PDL; compilation of combinations included - GCS   *
  78. ;    15 Aug 1984 - E.P.s for nL, LL and &L - GCS          *
  79. ;    29 Jun 1984 - @ fixed for word-size tbl entries - GCS *
  80. ;    *******************************************************
  81.  
  82. ;    =======================================================
  83. ;    The nucleus of REC is a compiler for control symbols,
  84. ;    operators and predicates, some auxiliary subroutines,
  85. ;    and an initilazation routine.
  86. ;
  87. ;    The compiler proper uses only the folowing external
  88. ;    references:
  89. ;
  90. ;        RAM storage        xpd, ypd, zpd
  91. ;        I-O routine        read
  92. ;        skip instruction    skp
  93. ;
  94. ;    The RAM storage must be initialized, which may be
  95. ;    accomplished by calling inre.
  96. ;
  97. ;    The location in which the object code is placed is
  98. ;    passed along through the register pair (dx), which is
  99. ;    continually updated to reflect the next available byte.
  100. ;    None of the other registers are either conserved nor
  101. ;    significant after the completion of compilation.
  102. ;
  103. ;    The usage of the registers is the following
  104. ;
  105. ;        pair (cx) contains the execution pointer
  106. ;        pair (dx) contains the object program counter
  107. ;        pair (bx) contains the compiling address
  108. ;
  109. ;    =======================================================
  110.  
  111. ;    Equivalences defining INTEL 8086 instructions and some
  112. ;    constants.
  113.  
  114. CA    equ    0E8H        ;call w/16 bit displacement
  115. JU    equ    0E9H        ;jump w/16 bit displacement
  116. RN    equ    0C3H        ;return w/o change of segment
  117. POBX    equ    05BH        ;pop bx
  118. PUBX    equ    053H        ;push bx
  119. JUBX    equ    0E3FFH        ;jmp bx
  120. PUME    equ    036FFH        ;push direct address
  121. POME    equ    0068FH        ;pop into memory
  122. INBX    equ    043H        ;inc bx
  123. LDME    equ    006C7H        ;ld mem,imm
  124.  
  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. QMOV:    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.     mov    di,bx
  329.     jcxz    qu1
  330.     cld
  331.     mov    bp,ds
  332.     mov    es,bp
  333. qu0:    movs    byte ptr [di],cs:[si]
  334.     loop    qu0
  335. qu1:    mov    PY,di
  336.     ret
  337.  
  338. ;    -------------------------------------------------------
  339. ;    Comments are enclosed in square brackets, which must be
  340. ;    balanced.  Code may be disabled by enclosing it in
  341. ;    square brackets, but care must be taken that the
  342. ;    expression so isolated does not contain individual
  343. ;    brackets, such as arguments of arrobas or quoted
  344. ;    brackets, which might disrupt the balance. Since
  345. ;    comments are ignored by the compiler they are not
  346. ;    executed.
  347. ;    -------------------------------------------------------
  348.  
  349. ;    Compile comments by ignoring them.
  350.  
  351. RECCM:    call    word ptr read        ;get next character
  352.     cmp    al,']'        ;test for closing ]
  353.     jz    RECCX        ;if so we're done
  354.     cmp    al,'['        ;test for beginning of new level
  355.     jnz    RECCM        ;otherwise keep on reading
  356.     call    RECCM        ;if so go after it recursively
  357.     jmp    RECCM
  358. RECCX:    ret
  359.  
  360. ;    -------------------------------------------------------
  361. ;    Sometimes, notably in compiling arroba as a call to a
  362. ;    subroutine named by a single letter, a parameter will
  363. ;    follow a subroutine call as its calling sequence.
  364. ;    -------------------------------------------------------
  365.  
  366. ;    Operator with one ASCII parameter.
  367.  
  368. RECO1:    call    RECOP        ;always compile the subroutine call
  369.     call    word ptr read        ;read the parameter
  370.     mov    bx,dx
  371.     mov    cs:[bx],al        ;store as a 1-byte calling sequence
  372.     inc    dx        ;always ready for next byte
  373.     ret
  374.  
  375. ;    Predicate with one ASCII parameter.
  376.  
  377. RECP1:    call    RECO1        ;compile as the analogous operator
  378.     jmp    RECYJ        ;then take account of false exit
  379.  
  380. ;    Predicate, with lookahead, to compile often-used
  381. ;    combinations like Ez and ED.
  382.  
  383. RECPL:    call    RECOL        ;compile as the analogous operator
  384.     jmp    short pl0    ;short jump because recol may skip
  385.     call    RECYJ        ;call to link into chain
  386.     jmp    skp86        ;skip, we have next character
  387. pl0:    jmp    RECYJ        ;no skip, just link into chain
  388.  
  389. ;    Operator, with lookahead, to compile often-used
  390. ;    combinations like pG and TL into a single call
  391.  
  392. RECOL:    mov    bl,al        ;save first character
  393. ol1:    call    word ptr read    ;get the next valid character
  394.     call    svc86
  395.     jmp    short ol1
  396.     add    al,' '        ;restore to ASCII
  397.     push    ax        ;save, in case combination not found
  398.     push    cx        ;save exec addr of first letter
  399.     push    dx        ;as well as compilation ptr
  400.     mov    bh,al        ;both letters in BX
  401.     mov    dx,CMT        ;combination table address
  402.     xchg    bx,dx        ;switch letters and address
  403. ol2:    mov    cx,[bx]        ;get next combination
  404.     jcxz    ol4        ;end of table, exit loop
  405.     cmp    cx,dx        ;else compare letters
  406.     jz    ol3        ;exit loop if found
  407.     add    bx,4        ;advance pointer to table
  408.     jmp    short ol2    ;try next
  409.  
  410. ol3:    pop    dx        ;found, get comp. ptr.
  411.     pop    cx        ;get rid of old exec addr
  412.     mov    cx,2[bx]    ;get exec. addr. of combination
  413.     pop    ax        ;get rid of saved character
  414.     jmp    RECOP        ;off to compile call
  415.  
  416. ol4:    pop    dx        ;not found, fetch comp. ptr.
  417.     pop    cx        ;and exec. addr. of first letter
  418.     call    RECOP        ;compile that
  419.     pop    ax        ;retrieve the second character
  420.     jmp    skp86        ;and skip, since no read necessary
  421.  
  422. ;    -------------------------------------------------------
  423. ;    Decimal numbers are of such frequent occurrence in the
  424. ;    form of counters, arguments, or just data that it is
  425. ;    convenient to compile them on sight without requiring
  426. ;    any special delimiters.  Likewise, negative numbers are
  427. ;    easier to designate using a minus sign than using their
  428. ;    modular form, but this should not prevent the use of a
  429. ;    minus sign as an operator.
  430. ;    -------------------------------------------------------
  431.  
  432. ;    Compile a minus sign. This involves determining whether
  433. ;    it is followed immediately by a decimal digit, in which
  434. ;    case it is compiled as part of a negative number.
  435.  
  436. RECMS:    mov    FRST,al        ;save the minus sign just in case
  437.     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:    cmp    al,'.'        ;period indicates an FP number
  445.     jz    ms2
  446.     call    RND        ;return if not digit
  447.     add    al,'0'        ;otherwise restore to ascii
  448. ms2:    inc    sp        ;erase call to ms1
  449.     inc    sp
  450.     push    dx        ;save compilation pointer
  451.     call    RECDS        ;read and convert digit string
  452.     mov    cx,cs:GNU    ;fake that it was nu, not ms
  453.     jmp    DD1        ;continue as though positive number
  454.  
  455. GNU    dw    NU
  456.  
  457. ;    Execute a number, which means load it on pdl.
  458.  
  459. NU:    pop    bx        ;get beginning of calling sequence
  460.     mov    cl,cs:[bx]    ;fetch length from code segment
  461.     mov    ch,0
  462.     inc    bx        ;point to low-order byte of number
  463.     jmp    QMOV        ;and use code at QU to do the move
  464.  
  465. ;    =======================================================
  466. ;    Some simple procedures to compile REC expressions into
  467. ;    subroutines, deposit a reference to them in a symbol
  468. ;    table, and eventually to recover the space and erase
  469. ;    the symbol table reference.
  470. ;    =======================================================
  471.  
  472. ;    Table search. The table whose address is stored at fxt
  473. ;    is consulted for its pair of addresses at position 4*A.
  474. ;    Thus on entry, A holds the table index.  This table
  475. ;    alternates the address of a compiling subroutine with
  476. ;    the execution address of the same entry.  On exit, (cx)
  477. ;    holds the execution address, (dx) is preserved, and a
  478. ;    jump is made to the compiling address.
  479.  
  480. rects:    mov    ah,0
  481.     mov    bp,ax        ;save the character
  482.     add    ax,ax
  483.     add    ax,ax
  484.     mov    bx,FXT        ;load base address of table
  485.     add    bx,ax
  486.     mov    ax,bp        ;restore letter to AX
  487.     add    al,' '        ;but in original ASCII form
  488.     push    word ptr [bx]        ;put the first entry in (cx)
  489.     mov    cx,2[bx]    ;table pointer is going
  490.     ret            ;then off to the compilation
  491.  
  492. ;    Pick out left delimiters: (, {, or [.
  493.  
  494. left:    call    word ptr read
  495.     cmp    al,'('
  496.     jz    eft
  497.     cmp    al,'{'
  498.     jz    eft
  499.     cmp    al,'['
  500.     jnz    left
  501.     call    reccm
  502.     jmp    short left
  503. eft:    ret
  504.  
  505. ;    A main program to compile characters one by one as
  506. ;    they are read in from the console.  Note that the
  507. ;    compiling programs invoked by rects can generate skips
  508. ;    when they have already read the following character.
  509. ;    This occurs most notably when compiling digits. Also
  510. ;    note that svc86 normalizes characters when it accepts
  511. ;    them.
  512.  
  513. recre:    call    word ptr read    ;read a character from whereever
  514. recrr:    call    svc86        ;check for space, control character
  515.     jmp    short recre    ;not valid, go back for another
  516.     call    rects        ;look up in table and compile it
  517.     jmp    short recre    ;read another character and repeat
  518.     jmp    short recrr    ;repeat but next character already read
  519.  
  520. ;    A subroutine which will pass over comments, and wait
  521. ;    for an opening left parenthesis or brace before compiling
  522. ;    a REC expression.
  523.  
  524. EMCE:    call    UCL        ;entry here erases an argument from PDL
  525. EMCX:    call    left        ;get a character from whereever
  526.     mov    dx,C1
  527.     mov    bx,C1
  528.     mov    bp,sp
  529.     xchg    bx,[bp]
  530.     push    bx
  531.     call    recrr        ;compiling prgrm one char already read
  532.     cmp    dx,C2
  533.     ja    emc0        ;error if above high limit
  534.     cmp    dx,C0
  535.     jb    emc0        ;error if below low limit
  536.     mov    C1,dx
  537.     ret
  538. emc0:    mov    bx,'pC'        ;type Cp ovfl and quit
  539.     jmp    FERR
  540.  
  541. EMCU:    pop    dx
  542.     pop    bx
  543.     push    dx
  544.     push    bx
  545.     mov    dx,(offset EMCV)
  546.     push    dx
  547.     jmp    bx
  548. EMCV:    jmp    EMCW
  549.     pop    C1
  550.     jmp    skp86
  551. EMCW:    pop    C1
  552.     ret
  553.  
  554. ;    ({) Introduce a series of definitions.
  555.  
  556. LBR:    xchg    bx,dx
  557.     mov    cs:byte ptr [bx],CA    ;insert a call to the executable
  558.     xchg    bx,dx            ; subroutine
  559.     inc    dx
  560.     mov    cx,dx        ;place to put call address - keep in BC
  561.     inc    dx        ;make room
  562.     inc    dx
  563.     call    RECYJ        ;link in the FALSE exit
  564.     call    RECJU
  565.     push    bx        ;keep this address
  566.     push    XPD
  567.     mov    XPD,0        ;this is top level for ensuing subroutines
  568.     mov    bx,0
  569. LB1:    push    dx        ;record entry point to subroutine
  570.     inc    bx        ;increment count of subroutines
  571.     push    bx        ;keep it next to top on stack
  572.     push    cx        ;jump address at entry - keep it on top
  573.     call    left
  574.     call    recrr        ;compile at least one subroutine
  575. LB2:    call    word ptr read        ;get possible name of subroutine
  576.     cmp    al,'}'        ;no name - we execute this one
  577.     jz    LB3
  578.     call    svc86        ;convert name into serial number
  579.     jmp    short LB2    ;punctuation instead of name
  580.     add    al,' '
  581.     mov    ah,0
  582.     mov    bx,VRT
  583.     add    ax,ax
  584.     add    bx,ax
  585. ;    add    bx,ax        ;word-sized entries
  586.     pop    cx        ;get this out of the way
  587.     mov    bp,sp
  588.     xchg    bx,[bp]        ;store table address, put subr count in bx
  589.     jmp    LB1
  590. LB3:    cld
  591.     mov    ax,cs
  592.     mov    es,ax
  593.     pop    bx        ;origin of brace compilation
  594.     mov    di,dx
  595.     lea    ax,2[bx]
  596.     sub    ax,di
  597.     neg    ax
  598.     mov    cs:[bx],ax
  599.     pop    cx        ;number of subroutines + 1
  600.     push    cx        ;we'll need it again later
  601.     mov    bp,cx        ;put it in bp too
  602.     dec    bp
  603.     add    bp,bp
  604.     add    bp,bp
  605.     add    bp,sp
  606.     mov    al,POBX
  607.     stosb
  608.     jmp    LB5
  609. LB4:    mov    ax,PUME    ;for each defined symbol we insert the
  610.     stosw
  611.     mov    ax,[bp]
  612.     stosw
  613.     mov    ax,LDME    ;
  614.     stosw
  615.     mov    ax,[bp]
  616.     stosw
  617.     mov    ax,2[bp]
  618.     stosw
  619.     sub    bp,4        ;we read the stack backwards
  620. LB5:    loop    LB4
  621.     mov    al,PUBX
  622.     stosb
  623.     mov    al,CA
  624.     stosb
  625.     pop    cx
  626.     pop    ax
  627.     sub    ax,di
  628.     dec    ax
  629.     dec    ax
  630.     stosw
  631.     push    cx
  632.     mov    al,JU        ;    jmp    $+6
  633.     stosb
  634.     push    di        ;    inx    h
  635.     inc    di        ;    inx    h
  636.     inc    di        ;    inx    h
  637.     mov    al,POBX
  638.     stosb
  639.     mov    al,INBX
  640.     stosb
  641.     stosb
  642.     stosb
  643.     mov    al,PUBX
  644.     stosb
  645.     pop    bx
  646.     lea    ax,2[bx]
  647.     sub    ax,di
  648.     neg    ax
  649.     mov    cs:[bx],ax
  650.     mov    al,POBX
  651.     stosb
  652.     pop    cx
  653.     jmp    LB7
  654. LB6:    mov    ax,POME    ;after an expression in braces is
  655.     stosw
  656.     pop    ax
  657.     stosw
  658.     inc    sp
  659.     inc    sp
  660. LB7:    loop    LB6
  661.     mov    ax,JUBX    ;the whole thing is finished off by a return
  662.     stosw
  663.     mov    dx,di
  664.     pop    XPD
  665.     pop    bx
  666.     cmp    XPD,0
  667.     jz    LB8
  668.     lea    ax,2[bx]
  669.     sub    ax,dx
  670.     neg    ax
  671.     mov    cs:[bx],ax
  672.     ret
  673. LB8:    mov    cx,cs:[bx]
  674.     mov    ax,(offset SKP)-2    ;top level true return
  675.     sub    ax,bx
  676.     mov    cs:[bx],ax
  677.     mov    cs:byte ptr (-4)[bx],RN    ;top level false return
  678.     inc    sp        ;return one level higher than expected
  679.     inc    sp
  680.     ret
  681.  
  682. ;    (@) Subroutine which will transform an ASCII character
  683. ;    into a table reference, and then jump to the address
  684. ;    so encountered.  This is essentially REC's subroutine
  685. ;    call mechanism, necessarily a predicate since it calls
  686. ;    a REC expression, which is itself a predicate.
  687.  
  688. AR:    pop    bx        ;entry if name is a parameter
  689.     mov    al,cs:[bx]    ;read the calling sequence
  690.     inc    bx        ;advance pointer for return
  691.     push    bx        ;put it back on 8080 stack
  692.     cmp    al,'@'
  693.     jnz    XAR
  694.     mov    bx,PX        ;argument on PDL, compute size
  695.     mov    ax,[bx]        ;but fetch two bytes anyway
  696.     mov    cx,PY
  697.     sub    cx,bx
  698.     call    UCL        ;lift it before going on
  699.     cmp    cx,2        ;is it an address?
  700.     jnz    XAR        ;no, assume a letter
  701.     jmp    ax        ;yes, jump to it
  702.  
  703. XAR:    mov    ah,0        ;clear the high byte
  704.     add    ax,ax        ;compute address of table entry
  705. ;    add    ax,ax        ;word-size entries
  706.     mov    di,ax
  707.     mov    bx,VRT        ;entry when index is in register A
  708.     jmp    word ptr [bx+di]        ;then use it as jump address
  709.  
  710. ;    =======================================================
  711. ;    Some general service routines.
  712. ;    =======================================================
  713.  
  714. ;    Skip on valid character, meaning, not control symbol.
  715. ;    If valid, 20H (space) is subtracted, making A = 1, etc.
  716.  
  717. svc86:    cmp    al,'!'        ;reject space, excl is lower limit
  718.     jb    sv
  719.     cmp    al,7FH        ;seven bits is upper limit
  720.     jnb    sv
  721.     sub    al,' '        ;normalize to begin with (excl) = 1
  722.     pop    bp
  723.     inc    bp
  724.     inc    bp
  725.     jmp    bp
  726. sv:    ret            ;don't skip for control or flag bit
  727.  
  728. ;    Second level return on error.
  729.  
  730. RR2:    pop    bx        ;entry to clear two items from PDL
  731.     mov    bp,sp
  732.     xchg    bx,[bp]        ;
  733. RR1:    pop    bx        ;entry to clear one item from PDL
  734.     mov    bp,sp
  735.     xchg    bx,[bp]        ;
  736. RER:    pop    ax        ;site where ther error occurred
  737.     cmp    ER,0        ;only record the first error
  738.     jnz    RRR
  739.     mov    ER,ax
  740. RRR:    ret
  741.  
  742. ;    (?)  Test whether an error has been reported: predicate
  743. ;    which is true if er is nonzero, in which case it will
  744. ;    reset er.  It will also, if TRUE, place the calling
  745. ;    address of the last reported error on the pushdown
  746. ;    list.  If false, only a FALSE return is generated. Note
  747. ;    the ironic circumstance that, if PDL is exhausted, qm
  748. ;    can generate an error trying to report an error - but
  749. ;    the TRUE result will still be valid.
  750.  
  751. QM:    cmp    ER,0        ;test the error cell
  752.     jz    QQ        ;FALSE return if no error
  753.     mov    cx,2        ;we want two bytes for error address
  754.     call    NARG        ;check space, prepare for new argument
  755.     mov    ax,ER        ;fetch error address
  756.     mov    [bx],ax        ;transfer it to REC PDL
  757.     inc    bx        ;
  758.     inc    bx        ;pointer must always advance
  759.     mov    PY,bx        ;end of the argument
  760.     mov    ER,0        ;reset ER
  761.     jmp    SKP        ;TRUE return - there was an error
  762. QQ:    ret
  763.  
  764. ;    Generate a skip (skp), whici is often combined with the
  765. ;    erasure og an argument on the pushdowo mist (cucl).
  766.  
  767. CUCL:    call    UCL        ;erase the top argument
  768. SKP:    pop    bp
  769.     add    bp,3        ;assume the skip will!be over a
  770.     jmp    bp        ;thsee-byte insuruction, such as a jump
  771.  
  772. skp86:    pop    bp
  773.     inc    bp
  774.     inc    bp
  775.     jmp    bp
  776.  
  777. ;    Test PDL space beginning at top argument. On entry (cx)
  778. ;    contains the total space required.  On exit, (cx) stays
  779. ;    unchanged, (dx) holds pz, while (bx) holds px+(cx).
  780. ;    If the space is not available, return is made from the
  781. ;    calling program after noting the error.  Otherwise
  782. ;    normal return to the calling program occurs. The likely
  783. ;    use of oarg is to record a result without having to go
  784. ;    through ucl, NARG.
  785.  
  786. OARG:    mov    dx,PZ        ;load limit of PDL
  787.     dec    dx        ;keep one byte margin
  788.     mov    bx,PX        ;load beginning of current argument
  789.     add    bx,cx
  790.     jc    NRER        ;error if PX+(cx) wraps around 64K
  791.     sub    dx,bx
  792.     jb    NRER        ;no, note error, quit program
  793.     ret            ;yes, continue normally
  794.  
  795. ;    Check space for, and then set up, a new argument. On
  796. ;    entry, (cx) should contain the amount of additional
  797. ;    space required.  The program will automatically add
  798. ;    two more bytes for the pointer which would close the
  799. ;    argument and then, if the required space is available,
  800. ;    close it, define the new px, and leave its value in
  801. ;    (bx).  (dx) will contain the old value of px to be used
  802. ;    in case the superseded argument is still interesting.
  803. ;    When space is not available, the error return rer is
  804. ;    taken.
  805. ;
  806. ;    The entry RARG can be taken when it is known that
  807. ;    sufficient space is available but the pointers still
  808. ;    have to be set up.
  809.  
  810. NARG:    mov    di,cx
  811.     mov    bx,PY        ;load end of current argument
  812.     lea    ax,3[bx+di]
  813.     cmp    ax,PZ
  814.     jnb    NRER        ;check available space
  815.     cmp    ax,PX
  816.     jb    NRER        ;error if ax wraps around 64K
  817. RARG:    mov    dx,PX        ;entry if no space check needed
  818.     mov    bx,PY
  819.     mov    [bx],dx        ;low byte of closing link
  820.     inc    bx        ;on to high byte
  821.     inc    bx        ;beginning of new space
  822.     mov    PX,bx        ;which is recorded by px
  823.     ret            ;and remains in (bx)
  824. NRER:    mov    bx,'DP'
  825.     jmp    FERR        ;advise of error and quit
  826.  
  827. ;    (&L)  Commonly used combination, eraseing only the lower arg
  828.  
  829. XLFT:    mov    si,PX
  830.     mov    cx,PY        ;pointers to top
  831.     sub    cx,si
  832.     call    UCL        ;"lift" top
  833.     test    dx,dx        ;empty PDL?
  834.     jz    xlre
  835.     call    UCL        ;lift the lower one
  836.     call    RARG        ;close the next
  837.     mov    di,bx        ;new px to di
  838.     cld
  839.     mov    ax,ds
  840.     mov    es,ax
  841.     repnz    movsb        ;move down the old top
  842.     mov    PY,di        ;record new end
  843. xlre:    ret
  844.  
  845. ;    (L)  Remove argument from pushdown list. There are no
  846. ;    requirements for entry to ucl.  On exit, (cx) remains
  847. ;    unchanged, (dx) holds the end of the former argument
  848. ;    and (bx) holds the beginning of the former argument -
  849. ;    the one that was exposed when the current argument was
  850. ;    erased. Erasing non-existent arguments creates an error
  851. ;    condition which is noted and ignored.
  852.  
  853. LFTW:    call    UCL        ;entry point for LL
  854.  
  855. UCL:    mov    bx,PX        ;pointer to current argument
  856.     dec    bx        ;just behind the present
  857.     dec    bx
  858.     mov    dx,[bx]        ;argument is the address
  859.     or    dx,dx        ;so we always test out of caution
  860.     jz    ULE
  861.     mov    PY,bx        ;(bx) now holds end of previous arg.
  862.     mov    PX,dx        ;pointer to beginning of prev. arg.
  863.     xchg    bx,dx
  864.     ret
  865. ULE:    inc    bx        ;restore bx to px
  866.     inc    bx
  867.     call    RER        ;record error if pointer was zero
  868.  
  869. ;    Null program for undefined operators.
  870.  
  871. NOOP:    ret
  872.  
  873. ;    =======================================================
  874. ;
  875. ;    Some of the service routines, which might be external
  876. ;    references in other modules, are:
  877. ;
  878. ;        oarg    space when reusing an argument
  879. ;        NARG    close old argument, space for new
  880. ;        rarg    same as NARG when space is assured
  881. ;        skp    generic skip
  882. ;        rer    return on error
  883. ;        rr2    rer after popping two addresses
  884. ;        rtn    generic return
  885. ;        ucl    lift argument from PDL (L)
  886. ;        cucl    lift argument, then skip
  887. ;
  888. ;    Three entry points can be used according to the variant
  889. ;    of the compiling operator C desired.  One of them could
  890. ;    also be used by a main program.
  891. ;
  892. ;        emce    lift pushdown, open block, compile
  893. ;        emcx    compile a sequence of subroutines
  894. ;
  895. ;    =======================================================
  896.  
  897. ;    END
  898.