home *** CD-ROM | disk | FTP | other *** search
-
-
- ; *******************************************************
- ; * REC module containing the REC nucleus and some of *
- ; * the really indispensable operators and predicates *
- ; * such as those defining two byte binary numbers and *
- ; * ASCII constant strings. The model of a pushdown *
- ; * list is assumed in the expectation that additional *
- ; * operators and predicates will also follow reversed *
- ; * Polish notation. There are additionally many small *
- ; * service routines which may be used externally. *
- ; * *
- ; * The source language for these programs is the one *
- ; * introduced by SORCIM for ACT86.COM, which is not *
- ; * quite the same that Intel's ASM86 uses. *
- ; * *
- ; * REC86 was obtained from the previously existing *
- ; * REC80 by applying SORCIM's TRANS86 translator and *
- ; * then adjusting the resulting code manually. It is *
- ; * intended that REC86 will be functionally identical *
- ; * to REC80. All error corrections, additions, or *
- ; * alterations are made simultaneously to the two *
- ; * programs, when they are not purely cosmetic. *
- ; * Braces, creating a different style of subroutine *
- ; * definition, were incorporated in REC at the time *
- ; * the translation to the Intel 8086 was made. *
- ; * *
- ; * REC86 contains the following compiling entries: *
- ; * *
- ; * reclp left parenthesis *
- ; * recco colon *
- ; * recsc semicolon *
- ; * recrp right parenthesis *
- ; * recop operator *
- ; * recpr predicate *
- ; * recsq single quotes *
- ; * recdq double quotes *
- ; * reccm comments *
- ; * reco1 operator with one ASCII parameter *
- ; * recp1 predicate with one ASCII parameter *
- ; * recms unary minus sign *
- ; * recdd decimal digit *
- ; * *
- ; * REC86 contains the following operators and *
- ; * predicates: *
- ; * *
- ; * ' single quote *
- ; * " double quote *
- ; * nu two byte decimal number *
- ; * O decimal ASCII string to number *
- ; * # number to decimal ASCII string *
- ; * L erase argument (lift) *
- ; * @ execute subroutine *
- ; * { initiate program segment *
- ; * } discontinue program segment *
- ; * ? report detected error *
- ; * *
- ; * The following are initialization programs which *
- ; * can be called at the outset of a compilation. *
- ; * *
- ; * inre initialize REC temporary registers *
- ; * *
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * *
- ; * REC86 - Copyright (C) 1982 *
- ; * Universidad Autonoma de Puebla *
- ; * All Rights Reserved *
- ; * *
- ; * [Harold V. McIntosh, 25 April 1982] *
- ; * *
- ; 14 April 1983 - AR recognizes @@ *
- ; 14 April 1983 - cosmetic changes: use of <lea> *
- ; 14 April 1983 - suppress TLU and TLV *
- ; 14 January 1984 - 4 explicit jmps's for sorcim.cnv *
- ; *******************************************************
-
- ; =======================================================
- ; The nucleus of REC is a compiler for control symbols,
- ; operators and predicates, some auxiliary subroutines,
- ; and an initilazation routine.
- ;
- ; The compiler proper uses only the folowing external
- ; references:
- ;
- ; RAM storage xpd, ypd, zpd
- ; I-O routine read
- ; skip instruction skp
- ;
- ; The RAM storage must be initialized, which may be
- ; accomplished by calling inre.
- ;
- ; The location in which the object code is placed is
- ; passed along through the register pair (dx), which is
- ; continually updated to reflect the next available byte.
- ; None of the other registers are either conserved nor
- ; significant after the completion of compilation.
- ;
- ; The usage of the registers is the following
- ;
- ; pair (cx) contains the execution pointer
- ; pair (dx) contains the object program counter
- ; pair (bx) contains the compiling address
- ;
- ; =======================================================
-
- ; Equivalences defining INTEL 8086 instructions and some
- ; constants.
-
- CA equ .0E8H ;call w/16 bit displacement
- JU equ .0E9H ;jump w/16 bit displacement
- RN equ .0C3H ;return w/o change of segment
- POBX equ .05BH ;pop bx
- PUBX equ .053H ;push bx
- JUBX equ .0E3FFH ;jmp bx
- PUME equ .036FFH ;push direct address
- POME equ .0068FH ;pop into memory
- INBX equ .043H ;inc bx
- LDME equ .006C7H ;ld mem,imm
- ZE equ .0000H ;zero
- FF equ .00FFH ;one byte complement of zero
-
-
- ; =============
- org 0100H
- ; =============
-
-
- jmp main ;<===============================<<<
-
-
- ; Compile a left parenthesis.
-
- RECLP: pop bp
- push ZPD ;save the linkage to semicolon exits
- push YPD ;save the higher linkage to false jumps
- push XPD ;save the repeat references
- mov ax,(offset ZE) ;initialze the new chains
- mov ZPD,ax ;null TRUE exit list
- mov YPD,ax ;null FALSE jump list
- mov XPD,dx ;new parenthesis level begins here
- jmp bp
-
- ; Compile a colon.
-
- RECCO: mov bx,XPD ;pick up reference to left parenthesis
- sub bx,dx
- lea bx,-3[bx]
- call RECJU ;and insert a jump to its location
- jmp RECFY ;fill in any FALSE predicate jumps
-
- ; Compile a semicolon.
-
- RECSC: mov bx,ZPD ;pick up link to TRUE exit chain
- call RECJU ;insert this one on it too
- mov ZPD,bx ;store it as the new head of the chain
- jmp RECFY ;fill in any FALSE predicate jumpe
-
- ; Compile an operator.
-
- RECOP: xchg bx,dx
- mov byte ptr [bx],(offset CA) ;store the 8086 code for a call
- lea bx,3[bx] ;advance (dx) to receive next byte
- sub cx,bx
- mov -2[bx],cx
- xchg bx,dx
- ret
-
- ; Compile a predicate.
-
- RECPR: call RECOP ;call its subroutine, same as operator
- RECYJ: mov bx,YPD ;linkage to FALSE exits
- call RECJU ;incorporate a jump if result FALSE
- mov YPD,bx ;update for new head of chain
- ret
-
- ; Compile a right parenthesis.
-
- RECRP: pop bp ;recover xpd, which is hidden
- pop XPD ;replace it
- cmp XPD,(offset ZE)
- jz RECFP ;if so, continue with recfp
- pop bx ;recover wpd
- call RECJU ;link expr to ypd on its own level
- push bx ;but save pointer until we finish up
- call RECFY ;false predicates in last segment
- pop YPD ;replace ypd for higher level
- mov bx,ZPD ;now we have destination for semicolons
- call recfc ;so insert all the correct addresses
- pop ZPD ;replace old zpd
- jmp bp
-
- ; Final right parentheses get a different treatment.
-
- RECFP: mov bx,dx ;compile pointer in bx
- mov byte ptr [bx],(offset RN) ;store a <ret> for false exit
- inc bx ;ready for next byte
- push bx ;save compile pointer
- mov dx,(offset SKP) ;address of skip - TRUE exit from REC
- call RECFY ;use it for last segment
- mov bx,ZPD ;destination of semicolons now known
- call recfc ;so fill out that chain
- pop dx ;compile pointer that was saved
- pop YPD ;restore old ypd
- pop ZPD ;restore old zpd
- ret ;return one level higher than expected
-
- ; Insert a new element in a chain of jmp's which will
- ; eventually have destination addresses. In the interim
- ; each is given the address of its predecessor. On entry
- ; (dx) holds the address where the instruction will be
- ; stored and (bx) holds the address of its predecessor.
- ; On exit, (dx) is incremented by 3 to point to the next
- ; free byte, and (bx) has the starting value of (dx).
-
- RECJU: xchg bx,dx ;(bx) and (dx) exchanged is better
- mov byte ptr [bx],(offset JU) ;store the jump instruction
- inc bx
- mov [bx],dx ;store old link
- lea dx,2[bx]
- ret
-
- ; When the destination of a linked chain of jumps is
- ; finally known, the destination can be substituted into
- ; each one of the links. On entry, (bx) contains the
- ; address of the first link unless it is zero signifying
- ; a null chain.
-
- recfc: or bx,bx ;test for end of chain
- jz recfx ;if address is zero, chain ends
- mov ax,dx
- dec ax
- dec ax
- recfi: mov cx,[bx] ;save next link
- mov [bx],ax ;store destination
- sub word ptr [bx],bx
- mov bx,cx ;update link
- or bx,bx
- jnz recfi ;continue
- recfx: ret
-
- ; Call recfc with the intention of filling the y chain.
-
- RECFY: mov bx,YPD
- call recfc
- mov YPD,bx
- ret
-
- ; Subroutine which will initialize the temporary
- ; registers used by the REC compiler.
-
- INRE: mov bx,(offset ZE)
- mov XPD,bx
- mov YPD,bx
- mov ZPD,bx
- ret
-
-
- ; =======================================================
- ; The following are specialized compiling subroutines
- ; which apply to special structures and depend on the
- ; model of a pushdown list with a linked chain structure
- ; and special registers px and py delimiting the top
- ; segment on the chain.
- ; =======================================================
-
- ; -------------------------------------------------------
- ; Compilation of quoted expressions. Single and double
- ; quotes may alternate with one another to an arbitrary
- ; depth. Both kinds of quotes are executed in the same
- ; way, by loading the quoted expression from the program
- ; onto the pushdown list.
- ; -------------------------------------------------------
-
- ; Compile single quotes.
-
- RECSQ: call RECOP ;record call to qu
- inc dx ;set aside two bytes
- inc dx ;to hold length of ASCII chain
- push dx ;keep beginning for future reference
- push QUEN ;delay cleanup until ret
- SQ: mov bp,read ;read the next character
- call bp
- cmp al,'''' ;test for single quote
- jz SQ2 ;if so go after entire chain
- cmp al,'"' ;test for double quotes
- jnz SQ1
- call DQ1 ;if so, read it all
- SQ1: xchg bx,dx
- mov [bx],al
- xchg bx,dx ;otherwise keep on storing
- inc dx ;and advancing pointer
- jmp SQ ;go after next character
- SQ2: ret
-
- ; Compile double quotes.
-
- RECDQ: call RECOP ;record call to qu
- inc dx ;set aside two bytes
- inc dx ;to hold length of chain
- push dx ;put chain origin away for reference
- push QUEN ;delay cleanup until ret
- DQ: mov bp,read ;read the next character
- call bp
- cmp al,'"' ;test for double quotes
- jz DQ2 ;if so, chain finished
- cmp al,'''' ;check for single quotes
- jnz DQ1
- call SQ1 ;if so go after whole chain
- DQ1: xchg bx,dx
- mov [bx],al
- xchg bx,dx ;otherwise keep on storing
- inc dx ;and advancing pointer
- jmp DQ ;go after next character
- DQ2: ret
-
- ; Cleanup for both quote compilers.
-
- QUEN dw ENQU ;for the direct push
- ENQU: pop bx ;beginning of chain in (bx)
- mov cx,dx
- sub cx,bx
- mov -2[bx],cx ;store length
- ret
-
- ; (') (") Execute single or double quote.
-
- QU: pop bx ;get call location off the 8080 stack
- mov cx,[bx] ;count
- inc bx ;
- inc bx ;
- mov si,bx ;save source origin
- add bx,cx ;calculate source end = return adress
- push bx
- call NARG ;check space, put dest. pointer in (bx)
- cld
- mov di,bx
- mov ax,ds
- mov es,ax
- mov ax,cs
- mov ds,ax
- repnz movs byte [di],[si]
- mov ax,es
- mov ds,ax
- mov PY,di ;record end of argument
- ret
-
- ; -------------------------------------------------------
- ; Comments are enclosed in square brackets, which must be
- ; balanced. Code may be disabled by enclosing it in
- ; square brackets, but care must be taken that the
- ; expression so isolated does not contain individual
- ; brackets, such as arguments of arrobas or quoted
- ; brackets, which might disrupt the balance. Since
- ; comments are ignored by the compiler they are not
- ; executed.
- ; -------------------------------------------------------
-
- ; Compile comments by ignoring them.
-
- RECCM: mov bp,read ;get next character
- call bp
- cmp al,']' ;test for closing ]
- jz RECCX ;if so we're done
- cmp al,'[' ;test for beginning of new level
- jnz RECCM ;otherwise keep on reading
- call RECCM ;if so go after it recursively
- jmp RECCM
- RECCX: ret
-
- ; -------------------------------------------------------
- ; Sometimes, notably in compiling arroba as a call to a
- ; subroutine named by a single letter, a parameter will
- ; follow a subroutine call as its calling sequence.
- ; -------------------------------------------------------
-
- ; Operator with one ASCII parameter.
-
- RECO1: call RECOP ;always compile the subroutine call
- mov bp,read ;read the parameter
- call bp
- mov bx,dx
- mov [bx],al ;store as a 1-byte calling sequence
- inc dx ;always ready for next byte
- ret
-
- ; Predicate with one ASCII parameter.
-
- RECP1: call RECO1 ;compile as the analogous operator
- jmp RECYJ ;then take account of false exit
-
- ; -------------------------------------------------------
- ; Decimal numbers are of such frequent occurrence in the
- ; form of counters, arguments, or just data that it is
- ; convenient to compile them on sight without requiring
- ; any special delimiters. Likewise, negative numbers are
- ; easier to designate using a minus sign than using their
- ; modular form, but this should not prevent the use of a
- ; minus sign as an operator.
- ; -------------------------------------------------------
-
- ; Compile a minus sign. This involves determining whether
- ; it is followed immediately by a decimal digit, in which
- ; case it is compiled as part of a negative number.
-
- RECMS: mov bp,read ;read in one byte
- call bp
- call MS1 ;decide whether it is a digit
- push ax ;it was not, save it
- call RECOP ;compile call to binary minus
- pop ax ;recover the extra character
- jmp skp86 ;skip because we have next character
-
- MS1: call RND ;return if not digit
- inc sp ;erase call to ms1
- inc sp ;
- call RECDS ;read and convert digit string
- mov cx,GNU ;fake that it was nu, not ms
- push ax ;save terminating character
- neg bx ;negate (bx)
- jmp DD1 ;continue as though positive number
-
- GNU dw NU
-
- ; Compile a decimal digit, which requires reading any
- ; further digits which follow, and saving the terminator.
-
- RECDD: ror al,1 ;undo multiplication by 4
- ror al,1 ;
- push cx ;save execution address
- call RECDS ;read and transform rest of digits
- pop cx ;recover execution address
- push ax ;recover terminating character
- DD1: call RECOP ;compile subroutine call
- xchg bx,dx ;(dx) and (bx) must be interchanged
- mov [bx],dx ;put low order byte in calling sequence
- inc bx ;
- inc bx ;ready for next byte
- xchg bx,dx ;put (dx) and (bx) back as they were
- pop ax ;recover terminating character
- jmp skp86 ;skip over character read call
-
- ; Multiply (bx) by 10 and add A. (dx) is conserved.
-
- TXP: mov cx,bx ;transfer (bx) to (cx)
- add bx,bx ;multiply (bx) by 2
- add bx,bx ;another 2 makes 4
- add bx,cx ;the original (bx) makes 5
- add bx,bx ;another 2 makes 10
- add bx,ax ;add in the accumulator
- ret
-
- ; The heart of number compilation.
-
- RECDS: and al,0FH ;mask ASCII down to binary value
- mov BL,al ;put it into register pair (bx)
- mov BH,(offset ZE) ;fill out H with a zero
- RD1: mov bp,read ;read the next character
- call bp
- call RND ;quit if it is not another digit
- call TXP ;multiply (bx) by ten and add A
- jmp RD1 ;continuing while digits keep coming
-
- ; Execute a number, which means load it on pdl.
-
- NU: mov cx,2 ;two bytes will be required
- call NARG ;close last argument, open new
- pop dx ;get beginning of calling sequence
- xchg bx,dx
- mov ax,[bx]
- xchg bx,dx
- mov [bx],ax ;and copy it over
- inc dx ;on to the high order byte
- inc bx ;and the place to store it
- inc dx ;move on to program continuation
- inc bx ;always leave PDL ready for next byte
- push dx ;put back the return address
- mov PY,bx ;mark end of the argument
- ret
-
- ; (O) Transform an ASCII character string on the PDL into
- ; a two-byte number. Predicate - false if the argument
- ; is not a digit string or null, leaving the argument
- ; unchanged.
-
- UCO: mov cx,2 ;two bytes are required
- call OARG ;check that they are available
- mov bx,PY ;fetch the end of the argument string
- mov byte ptr [bx],(offset ZE) ;put a zero there to mark its end
- mov dx,PX ;load pointer to argument string
- mov bx,(offset ZE) ;zero in (bx) to start the conversion
- O1: xchg bx,dx
- mov al,[bx]
- xchg bx,dx ;fetch one character
- inc dx ;get ready for next
- or al,al ;test for zero
- jz O2 ;go to accumulation phase
- call RND ;FALSE, chain unaltered if non-digit
- call TXP ;otherwise continue to work up value
- jmp O1 ;and keep on reading bytes
- O2: xchg bx,dx ;safeguard converted number in (dx)
- mov bx,PX ;get pointer to argument
- mov [bx],dx ;store low byte
- inc bx ;increment pointer
- inc bx ;increment pointer again
- mov PY,bx ;store to close argument
- jmp SKP ;TRUE exit from predicate
-
- ; (#) Change two-byte binary number into a decimal-based
- ; ASCII string without sign. The special cases of a zero-
- ; byte or a one-byte argument are also considered.
-
- NS: mov cx,05H ;five bytes may be required
- call OARG ;reuse the old argument
- mov cx,PY
- mov bx,PX
- sub cx,bx
- mov dx,(offset ZE) ;put zero in (dx) for default
- jcxz NS1 ;load nothing
- mov dl,[bx] ;load low byte
- dec cx ;test for one byte
- jcxz NS1 ;only byte and it's loaded
- mov dh,1[bx] ;load high byte
- NS1: push bx ;save pointer for ASCII string
- mov al,'0' ;prepare to write a zero
- mov bx,-10000 ;will there be 5 digits?
- add bx,dx ;
- jb NS2 ;
- mov bx,-1000 ;will there be 4 digits?
- add bx,dx ;
- jb NS3 ;
- mov bx,-100 ;will there be 3 digits?
- add bx,dx ;
- jb NS4 ;
- mov bx,-10 ;will there be 2 digits?
- add bx,dx ;
- jb NS5 ;
- jmp NS6 ;write one no matter what
- NS2: mov cx,-10000 ;ten thousands digit
- call NSA ;
- NS3: mov cx,-1000 ;thousands digit
- call NSA ;
- NS4: mov cx,-100 ;hundreds digit
- call NSA ;
- NS5: mov cx,-10 ;tens digit
- call NSA ;
- NS6: add al,dl ;units digit
- pop bx ;recover pointer to PDL
- mov [bx],al ;store the digit
- inc bx ;position pointer for next byte
- mov PY,bx ;done, store it as terminator
- ret
-
- NSA: mov bx,cx ;put power of ten in (bx)
- add bx,dx ;subtract it once
- jnb NSB ;can't subtract
- inc al ;increase the count
- xchg bx,dx ;put diminished number in (dx)
- jmp NSA ;repeat the cycle
- NSB: pop bp ;get <call nsa> return address
- pop bx
- mov [bx],al ;store new digit
- inc bx ;advance pointer
- mov al,'0' ;load a fresh ASCII zero
- push bx
- jmp bp ;return to the <call nsa>
-
- ; =======================================================
- ; Some simple procedures to compile REC expressions into
- ; subroutines, deposit a reference to them in a symbol
- ; table, and eventually to recover the space and erase
- ; the symbol table reference.
- ; =======================================================
-
- ; Table search. The table whose address is stored at fxt
- ; is consulted for its pair of addresses at position 4*A.
- ; Thus on entry, A holds the table index. This table
- ; alternates the address of a compiling subroutine with
- ; the execution address of the same entry. On exit, (cx)
- ; holds the execution address, (dx) is preserved, and a
- ; jump is made to the compiling address.
-
- rects: mov ah,(offset ZE)
- add ax,ax
- add ax,ax
- mov bx,FXT ;load base address of table
- add bx,ax
- push word ptr [bx] ;put the first entry in (cx)
- mov cx,2[bx] ;table pointer is going
- ret ;then off to the compilation
-
- ; Pick out left delimiters: (, {, or [.
-
- left: mov bp,read
- call bp
- cmp al,'('
- jz eft
- cmp al,'{'
- jz eft
- cmp al,'['
- jnz left
- call reccm
- jmps left
- eft: ret
-
- ; A main program to compile characters one by one as
- ; they are read in from the console. Note that the
- ; compiling programs invoked by rects can generate skips
- ; when they have already read the following character.
- ; This occurs most notably when compiling digits. Also
- ; note that svc86 normalizes characters when it accepts
- ; them.
-
- recre: mov bp,read ;read a character from whereever
- call bp
- recrr: call svc86 ;check for space, control character
- jmps recre ;not valid, go back for another
- call rects ;look up in table and compile it
- jmps recre ;read another character and repeat
- jmps recrr ;repeat but next character already read
-
- ; A subroutine which will pass over comments, and wait
- ; for an opening left parenthesis or brace before compiling
- ; a REC expression.
-
- EMCE: call UCL ;entry here erases an argument from PDL
- EMCX: call left ;get a character from whereever
- mov dx,C1
- mov bx,C1
- mov bp,sp
- xchg bx,[bp]
- push bx
- call recrr ;compiling prgrm one char already read
- mov C1,dx
- ret
-
- EMCU: pop dx
- pop bx
- push dx
- push bx
- mov dx,(offset EMCV)
- push dx
- jmp bx
- EMCV: jmp EMCW
- pop C1
- jmp skp86
- EMCW: pop C1
- ret
-
- ; ({) Introduce a series of definitions.
-
- LBR: xchg bx,dx
- mov byte ptr [bx],(offset CA) ;insert a call to the executable subroutine
- xchg bx,dx
- inc dx
- mov cx,dx ;place to put call address - keep in BC
- inc dx ;make room
- inc dx
- call RECYJ ;link in the FALSE exit
- call RECJU
- push bx ;keep this address
- push XPD
- mov XPD,(offset ZE) ;this is top level for ensuing subroutines
- mov bx,(offset ZE)
- LB1: push dx ;record entry point to subroutine
- inc bx ;increment count of subroutines
- push bx ;keep it next to top on stack
- push cx ;jump address at entry - keep it on top
- call left
- call recrr ;compile at least one subroutine
- LB2: mov bp,read ;get possible name of subroutine
- call bp
- cmp al,'}' ;no name - we execute this one
- jz LB3
- call svc86 ;convert name into serial number
- jmps LB2 ;punctuation instead of name
- add al,' '
- mov ah,(offset ZE)
- mov bx,VRT
- add bx,ax
- add bx,ax
- pop cx ;get this out of the way
- mov bp,sp
- xchg bx,[bp] ;store table address, put subr count in bx
- jmp LB1
- LB3: cld
- mov ax,ds
- mov es,ax
- pop bx ;origin of brace compilation
- mov di,dx
- mov [bx],di ;store displacement at initial jump
- sub word ptr [bx],bx
- dec word ptr [bx]
- dec word ptr [bx]
- pop cx ;number of subroutines + 1
- push cx ;we'll need it again later
- mov bp,cx ;put it in bp too
- dec bp
- add bp,bp
- add bp,bp
- add bp,sp
- mov al,(offset POBX)
- stos byte [di]
- jmp LB5
- LB4: mov ax,(offset PUME) ;for each defined symbol we insert the
- stos word [di]
- mov ax,[bp]
- stos word [di]
- mov ax,(offset LDME) ;
- stos word [di]
- mov ax,[bp]
- stos word [di]
- mov ax,2[bp]
- stos word [di]
- sub bp,4 ;we read the stack backwards
- LB5: loop LB4
- mov al,(offset PUBX)
- stos byte [di]
- mov al,(offset CA)
- stos byte [di]
- pop cx
- pop ax
- sub ax,di
- dec ax
- dec ax
- stos word [di]
- push cx
- mov al,(offset JU) ; jmp $+6
- stos byte [di]
- push di ; inx h
- inc di ; inx h
- inc di ; inx h
- mov al,(offset POBX)
- stos byte [di]
- mov al,(offset INBX)
- stos byte [di]
- stos byte [di]
- stos byte [di]
- mov al,(offset PUBX)
- stos byte [di]
- pop bx
- mov [bx],di
- sub word ptr [bx],bx
- dec word ptr [bx]
- dec word ptr [bx]
- mov al,(offset POBX)
- stos byte [di]
- pop cx
- jmp LB7
- LB6: mov ax,(offset POME) ;after an expression in braces is
- stos word [di]
- pop ax
- stos word [di]
- inc sp
- inc sp
- LB7: loop LB6
- mov ax,(offset JUBX) ;the whole thing is finished off by a return
- stos word [di]
- mov dx,di
- pop XPD
- pop bx
- cmp XPD,(offset ZE)
- jz LB8
- mov [bx],dx
- sub word ptr [bx],bx
- dec word ptr [bx]
- dec word ptr [bx]
- ret
- LB8: mov cx,[bx]
- mov [bx],(offset SKP)
- sub word ptr [bx],bx
- dec word ptr [bx]
- dec word ptr [bx]
- sub bx,cx
- mov [bx],dx
- sub word ptr [bx],bx
- dec word ptr [bx]
- dec word ptr [bx]
- xchg bx,dx
- mov [bx],(offset JUBX)
- inc bx
- inc bx
- xchg bx,dx
- inc sp
- inc sp
- ret
-
- ; (@) Subroutine which will transform an ASCII character
- ; into a table reference, and then jump to the address
- ; so encountered. This is essentially REC's subroutine
- ; call mechanism, necessarily a predicate since it calls
- ; a REC expression, which is itself a predicate.
-
- AR: pop bx ;entry if name is a parameter
- mov al,[bx] ;read the calling sequence
- inc bx ;advance pointer for return
- push bx ;put it back on 8080 stack
- cmp al,'@'
- jnz XAR
- NAR: mov bx,PX ;entry if subroutine index is argument
- mov al,[bx]
- call UCL
- XAR: mov ah,(offset ZE)
- add ax,ax
- mov di,ax
- mov bx,VRT ;entry when index is in register A
- jmp word ptr [bx+di] ;then use it as jump address
-
- ; =======================================================
- ; Some general service routines.
- ; =======================================================
-
- ; Skip on valid character, meaning, not control symbol.
- ; If valid, 20H (space) is subtracted, making A = 1, etc.
-
- svc86: cmp al,'!' ;reject space, excl is lower limit
- jb sv
- cmp al,7FH ;seven bits is upper limit
- jnb sv
- sub al,' ' ;normalize to begin with (excl) = 1
- pop bp
- inc bp
- inc bp
- jmp bp
- sv: ret ;don't skip for control or flag bit
-
- ; Return if not decimal. A unchanged if not decimal, else
- ; reduced to binary.
-
- RND: cmp al,':' ;colon follows 9 in ASCII alphabet
- jnb RTN
- cmp al,'0' ;ASCII zero is lower limit
- jb RTN
- sub al,'0' ;normalize to get binary values
- mov ah,(offset ze) ;zero for uncomplicated arithmetic
- ret
- RTN: inc sp
- inc sp
- ret
-
- ; Second level return on error.
-
- RR2: pop bx ;entry to clear two items from PDL
- mov bp,sp
- xchg bx,[bp] ;
- RR1: pop bx ;entry to clear one item from PDL
- mov bp,sp
- xchg bx,[bp] ;
- RER: pop ax ;site where ther error occurred
- cmp ER,(offset ZE) ;only record the first error
- jnz RRR
- mov ER,ax
- RRR: ret
-
- ; (?) Test whether an error has been reported: predicate
- ; which is true if er is nonzero, in which case it will
- ; reset er. It will also, if TRUE, place the calling
- ; address of the last reported error on the pushdown
- ; list. If false, only a FALSE return is generated. Note
- ; the ironic circumstance that, if PDL is exhausted, qm
- ; can generate an error trying to report an error - but
- ; the TRUE result will still be valid.
-
- QM: cmp ER,(offset ZE) ;test the error cell
- jz QQ ;FALSE return if no error
- mov cx,2 ;we want two bytes for error address
- call NARG ;check space, prepare for new argument
- mov ax,ER ;fetch error address
- mov [bx],ax ;transfer it to REC PDL
- inc bx ;
- inc bx ;pointer must always advance
- mov PY,bx ;end of the argument
- mov ER,(offset ZE) ;reset ER
- jmp SKP ;TRUE return - there was an error
- QQ: ret
-
- ; Generate a skip (skp), which is often combined with the
- ; erasure of an argument on the pushdown list (cucl).
-
- CUCL: call UCL ;erase the top argument
- SKP: xchg bx,sp
- inc word ptr [bx] ;assume the skip will be over a
- inc word ptr [bx] ;three-byte instruction, such as a jump
- inc word ptr [bx] ;
- xchg bx,sp
- ret ;return to the altered address
-
- skp86: xchg bx,sp
- inc word ptr [bx]
- inc word ptr [bx]
- xchg bx,sp
- ret
-
- ; Test PDL space beginning at top argument. On entry (cx)
- ; contains the total space required. On exit, (cx) stays
- ; unchanged, (dx) holds pz, while (bx) holds px+(cx).
- ; If the space is not available, return is made from the
- ; calling program after noting the error. Otherwise
- ; normal return to the calling program occurs. The likely
- ; use of oarg is to record a result without having to go
- ; through ucl, NARG.
-
- OARG: mov dx,PZ ;load limit of PDL
- dec dx ;keep one byte margin
- mov bx,PX ;load beginning of current argument
- add bx,cx
- sub dx,bx
- jb oar ;no, note error, quit calling program
- ret ;yes, continue normally
- oar: call RER ;this must be here to get a short jump
-
- ; Check space for, and then set up, a new argument. On
- ; entry, (cx) should contain the amount of additional
- ; space required. The program will automatically add
- ; two more bytes for the pointer which would close the
- ; argument and then, if the required space is available,
- ; close it, define the new px, and leave its value in
- ; (bx). (dx) will contain the old value of px to be used
- ; in case the superseded argument is still interesting.
- ; When space is not available, the error return rer is
- ; taken.
- ;
- ; The entry RARG can be taken when it is known that
- ; sufficient space is available but the pointers still
- ; have to be set up.
-
- NARG: mov di,cx
- mov bx,PY ;load end of current argument
- lea ax,3[bx+di]
- cmp ax,PZ
- jnb NRER ;check available space
- RARG: mov dx,PX ;entry if no space check needed
- mov bx,PY
- mov [bx],dx ;low byte of closing link
- inc bx ;on to high byte
- inc bx ;beginning of new space
- mov PX,bx ;which is recorded by px
- ret ;and remains in (bx)
- NRER: call RER
-
- ; (L) Remove argument from pushdown list. There are no
- ; requirements for entry to ucl. On exit, (cx) remains
- ; unchanged, (dx) holds the end of the former argument
- ; and (bx) holds the beginning of the former argument -
- ; the one that was exposed when the current argument was
- ; erased. Erasing non-existent arguments creates an error
- ; condition which is noted and ignored.
-
- UCL: mov bx,PX ;pointer to current argument
- dec bx ;just behind the present
- dec bx
- mov dx,[bx] ;argument is the address
- or dx,dx ;so we always test out of caution
- jz ULE
- mov PY,bx ;(bx) now holds end of previous arg.
- mov PX,dx ;pointer to beginning of prev. arg.
- xchg bx,dx
- ret
- ULE: call RER ;record error if pointer was zero
-
- ; Null program for undefined operators.
-
- NOOP: ret
-
- ; =======================================================
- ;
- ; Some of the service routines, which might be external
- ; references in other modules, are:
- ;
- ; oarg space when reusing an argument
- ; NARG close old argument, space for new
- ; rarg same as NARG when space is assured
- ; skp generic skip
- ; rer return on error
- ; rr2 rer after popping two addresses
- ; rtn generic return
- ; ucl lift argument from PDL (L)
- ; cucl lift argument, then skip
- ;
- ; Three entry points can be used according to the variant
- ; of the compiling operator C desired. One of them could
- ; also be used by a main program.
- ;
- ; emce lift pushdown, open block, compile
- ; emcx compile a sequence of subroutines
- ;
- ; =======================================================
-
- END
-
-
-