; ======================================================= ; REC module containing RAM storage, I/O programs, main ; program, and the directory. The complete set of modules ; comprises REC80.MAC, PDL80.MAC, MKV80.MAC, RECLIB.MAC, and ; FXT80.MAC. RECLIB.MAC may be omitted if the operator X ; isn't used, and must be substituted by another module ; if the collection of subroutines to be called by X is ; to be changed. ; ; FXT80.MAC contains the following REC operators and ; predicates: ; ; C compile a REC expression ; i input from designated port ; k call CP/M without residue ; K call CP/M, preserve FCB, return value ; o output from designated port ; R read one character from console ; t type message given header ; T type argument on PDL ; W write argument on LST: ; x execute REC subroutine ; ` test if a character waits at keyboard ; ; REC version released during the 1980 Summer School of ; the Microcomputer Applications Group of the I.C.U.A.P. ; ; FXT80 - Copyright (C) 1980 ; Universidad Autonoma de Puebla ; 49 Poniente 1102 - Puebla, Puebla, Mexico ; All Rights Reserved ; ; [Harold V. McIntosh, 28 August 1980] ; ; 1 January 1981 - get address of BIOS vector from rst0 ; 1 January 1981 - protect T with pushes, pops of DE, HL ; 1 January 1981 - memory reorganization ; 24 May 1981 - 0000 at bottom of PDL to restrain L ; 3 March 1982 - rewrite extension as REC - (FGZ) ; 25 March 1982 - Y is now a predicate ; 25 April 1982 - C is also a predicate, modified for {}'s ; 20 May 1983 - N is numerical comparison predicate ; 20 May 1983 - h has been withdrawn ; 28 May 1983 - ~ has been redefined ; 30 May 1983 - cpin: return to CP/M if file won't open ; 8 July 1983 - C has object program origin as argument ; 8 July 1983 - C is an operator ; 8 July 1983 - c0 defined as lower limit compile area ; 8 July 1983 - x has been moved from RECLIB.MAC ; 8 July 1983 - x predicate - to call REC subroutines ; 9 July 1983 - Buffered CP/M input if no disk file given ; 14 July 1983 - exchange arguments of W ; 21 July 1983 - partition available memory on entry ; ======================================================= ; Absolute program locations used by CP/M. rst0 equ 0000H boot equ rst0 ;CP/M bootstrap entry point bios equ rst0+1 ;CP/M BIOS reference point bdos equ rst0+5 ;CP/M I-O communication point emem equ rst0+6 ;where effective end of memory is stored tfcb equ 005CH ;CP/M file control block talt equ 006CH ;CP/M alternate file name fsiz equ 0010H ;CP/M file name size tbuf equ 0080H ;CP/M disk buffer location tsiz equ 0080H ;CP/M disk buffer size ; Useful constant. ze equ 00H ; Equivalences to other REC subroutines. ext noop ext ucl,cucl,narg,oarg ext miuc,mduc,putw,bcld,deld ext skp,req,seq,rer,rr2 ext psiz,siz,sng,sing ext left,recrr,onel ext recre,emce,emcu,emcv,emcx,ar,nar,inre ext twol ; ======================================================= ; Programs related to input-output and disk usage. ; ======================================================= ; Buffer read routine. pty: push h ;conserve HL lhld rx ;pointer to read buffer mov a,m ;fetch byte inx h ;advance pointer to next byte shld rx ;update buffer pointer pop h ;restore HL - preserve all reg pairs ret ; Console character read routine. Strict CP/M compatible ; version, which has characteristics undesirable for some ; applications, such as an automatic echo or preemption ; of some of the control characters for editing purposes. ; When it is used, programs must forego their own echo, ; and do their own editing when required. ;chin: push h ; push d ; push b ; mvi c,1 ;read from console ; call bdos ; pop b ; pop d ; pop h ; ret ; Version with direct access to CONIN. chin equ conin ; Buffered console character read routine, which is more ; practical for use with CP/M. buin: push h ;save 3 register pairs push d ; push b ; lhld ry ;buffer limit xchg ; lhld rx ;buffer pointer mov a,l ;check for exhausted buffer cmp e ; jnz bi5 ;buffer remnant available mov a,h ; cmp d ; jnz bi5 ;buffer remnant available mvi c,9 ;(09) write message lxi d,bume ;REC80 prompt call bdos ; mvi c,10 ;(0A) buffered read lxi d,tbuf ; call bdos ; mvi c,9 ;(09) write message lxi d,crlf ;CR,LF call bdos ; lxi h,tbuf+2 ;where the text begins shld rx ;buffer pointer dcx h ; mov e,m ;get occupancy mvi d,0 ;insert leading zero dad d ;calculate final address inx h ;plus one more - that's REC style shld ry ;buffer limit lhld rx ;buffer pointer bi5: mov a,m ;pick up the next character inx h ;ready for another shld rx ;buffer pointer pop b ;restore 3 registers pop d ; pop h ; ret logo: db 0DH,0AH,' REC(8080)/ICUAP',0DH,0AH db 'Universidad Autonoma de Puebla',0DH,0AH db ' November 20, 1983',0DH,0AH,'$' bume: db 0DH,0AH,'REC80> $' crlf: db 0DH,0AH,'$' ; Define the console buffer as the source code reader. bure: lxi h,tbuf ;the disk won't be using its buffer mvi m,tsiz-2 ;define its maximum length inx h ;text origin is two bytes on inx h ; shld rx ;buffer pointer shld ry ;buffer limit lxi h,buin ;buffered source from console shld re ;REC compiler's I-O linkage ret ; Console character out routine. Strict CP/M compatible ; version, which unfortunately makes so many tests and ; jumps that it is unsuitable for programs such as the ; cursor editor which frequently write a full screen. ;chou: push h ; push d ; push b ; mvi c,2 ;write character at console ; mov e,a ; call bdos ; pop b ; pop d ; pop h ; ret ; Version with fast access to conout. chou: push b mov c,a call conou pop b ret ; (`) Test for preesence of waiting character (FALSE if ; none waiting). ; ;chaw: mvi c,11 ; ; call bdos ; ; rrc ;bit 0 holds the relevant information ; rnc ;FALSE return if the bit is zero ; jmp skp ;TRUE return if it is set ; Version with fast access to const. It is required when ; the fast chin is used, because CP/M has some internal ; buffers which will otherwise distort the results. chaw: call const rrc rnc jmp skp ; Printer output routine. prou: push h push d push b mvi c,5 ;output through LST: mov e,a call bdos pop b pop d pop h ret ; (R) REC read operator. ucr: lxi b,1 ;one byte to be inserted call narg ;close last arg, verify space call tyin ;get byte from console input mov m,a ;store on PDL inx h ;advance pointer shld py ;save as terminator ret ; (t) Write indirect operator. prints the ; indicated message, leaves no residue. lct: lhld px ;fetch argument pointer call twol ;move two args to 8080 stack pop d ;second arg (org) into DE pop h ;top arg (siz) into HL dad d ;org+siz=end xchg ;DE=end, HL=org jmp ut1 ;use write cycle in UCT ; (T) REC write operator. <'XXX' T> will write XXX on ; the console, leaving it on the PDL. uct: lhld py ;fetch terminal address xchg ;put it in DE lhld px ;beginning address to HL ut1: mov a,e ;compare low bytes cmp l ; jnz ut2 ;don't match, keep writing mov a,d ;compare high bytes cmp h ; rz ;they match, we're done ut2: mov a,m ;get byte out of memory push h ;the registers DE and HL push d ;are essential for the loop call tyou ;send it to typeout pop d ;recover the saved registers pop h ; inx h ;advance pointer jmp ut1 ;repeat ; (W) REC print operator. will print the ; indicated text on the list device, and then erase its ; arguments. ucw: lhld px ;pointer to arguments call twol ;2 args from PDL to 8080 stack pop h ;place text origin in HL pop d ;place length in DE uww: mov a,e ;check for zero length ora d ;by superposing length bytes rz ;no more to print mov a,m ;fetch a byte push h ;we need to be sure that DE and HL are push d ;preserved whatever the print routine call prou ;send it to printer pop d ;recover HL pop h ;and DE dcx d ;diminish count inx h ;advance pointer jmp uww ;repeat ; (i) Input from designated port. leaves ; so that after disposing of , ; can be reused. lci: lhld px ;get pointer to top argument on PDL mov a,m ;only the low order byte matters sta qi ;place it in teme IN instruction lxi b,1 ;we're only going to read one byte call narg ;prepare a place for it on the PDL call qin ;execute the captive IN instruction mov m,a ;storing the incoming byte on the PDL inx h ;always ready for the next byte shld py ;close off the argument ret ;and we're through ; (o) Output from designated port - ; leaves , facilitating multiple OUTs through the ; same port. lco: lhld px ;pointer to last argument - output byte mov b,m ;tuck it into register b call ucl ;erase the top argument mov a,m ;HL points to next argument - get it sta qo ;store in tame OUT instruction mov a,b ;output must be from accumulator jmp qou ;execute the prepared OUT instruction ; ======================================================= ; ; Communication with CP/M takes two forms: ; which leaves on the pushdown list, or else ; which leaves nothing on the pushdown list. ; In either case - FCB is a two-byte parameter, usually ; the address of the file control block - but it could ; also be a DMA address or sometimes even null for the ; sake of uniformity. Approximately thirty options are ; available which are numbered serially, indicated by the ; argument n. The difference between K and k is that the ; former conserves the parameter FCB for possible use by ; a subsequent CP/M call, and reports a result in the ; one-byte result . This could be the character ; read by an input routine or an error code for the disk ; routines. ; ; The options are: ; ; num function "FCB" "code" ; --- -------- ----- ------ ; ; 0 system reset - - ; 1 read console - char ; 2 write console char - ; 3 read reader - char ; 4 write punch char - ; 5 write list char - ; 6 - - - ; 7 read i/o stat - stat ; 8 write i/ stat stat - ; 9 print buffer buffer - ; 10 read buffer buffer - ; 11 console status - stat ; ; 12 lift disk head - - ; 13 init disk only - - ; 14 select disk disk - ; 15 open file fcb code ; 16 close file fcb code ; 17 search once fcb code ; 18 search again fcb code ; 19 delete file fcb code ; 20 read 1 record fcb code ; 21 write 1 record fcb code ; 22 create file fcb code ; 23 rename file fcb code ; 24 read login - logv ; 25 read disklog - disk ; 26 set DMA address dma - ; 27 read bitmap - - ; ; Fuller details of all the CP/M options and the way they ; function can be obtained through consulting Digital ; Research's manuals for CP/M, especially their "CP/M ; Interface Guide." ; ; ======================================================= ; (K) Set up communication with CP/M - top into BC, ; next into DE. Preserve next, call BDOS, (Aze) into ; top. cpm: lhld px ;fetch pointer to top argument mov c,m ;load C from low byte inx h ;next byte mov b,m ;load B from high byte lhld px ;pointer to top argument again dcx h ;high byte, pointer to prev arg mov d,m ;load up DE with high byte dcx h ;low byte, pointer to prev arg mov e,m ;finish loading DE xchg ;pointer into HL mov e,m ;low byte of under argument inx h ;advance pointer mov d,m ;high byte of under argument call bdos ;call BDOS with args in BC, DE lhld px ;pointer to top argument again mov m,a ;save low byte from A inx h ;on to high byte mvi m,ze ;make high byte a zero ret ; (k) Call to CP/M without any value returned. cpml: call bcld ;load top arg into BC, lift it call deld ;load next arg into DE, lift it too jmp bdos ;execute indicated operation ; ------------------------------------------------------- ; Disk input-output routine working through CP/M. ; ------------------------------------------------------- ; Set up a file control block with a given file name and ; the default extension REC. The pushdown list contains ; the disk unit designation, then by the filename without ; any extension. No protection is afforded against an ; overly long file name, a nonexistent disk, or the like. ; Some errors of this type must be caught by CP/M since ; REC cannot know such things as the exact number of disk ; drives that there will be. diin: mvi b,21H ;FCB requires 33 bytes lxi h,tfcb ;use CP/M's transient FCB mvi a,00H ;fill it with zeroes di1: mov m,a ;loop for block zero inx h ;advance pointer dcr b ;reduce count jnz di1 ;repeat until count vanishes mvi b,8 ;filename field is 8 bytes long lxi h,tfcb+1 ;field begins at second byte mvi a,' ' ;fill it with blanks di2: mov m,a ;loop for block of blanks inx h ;advance pointer dcr b ;reduce count jnz di2 ;repeat until count vanishes mvi m,'R' ;place 'REC' in extension field inx h ; mvi m,'E' ; inx h ; mvi m,'C' ; lhld px ;fetch pointer to top argument mov a,m ;load disk unit designator sui '@' ;normalize to uppercase letters sta tfcb ;store it in file control block call ucl ;pop top argument lhld px ;fetch pointer to file name xchg ;place it in DE for source lhld py ;end of file name call siz ;place py - px in BC lxi h,tfcb+1 ;destination origin call miuc ;move by increment until count cpin: lda tfcb+1 cpi ' ' jz boot ;no file given, so quit mvi c,15 ; lxi d,tfcb ;file control block call bdos ; cpi 0FFH ;check for error jz boot ;don't hang system; so quit instead lxi h,tbuf ;origin of CP/M's sector buffer shld rx ;initial address of pseudotty shld ry ;provoke disk read ret ; Read from disk buffer, replenish buffer when empty. dire: push h ;save 3 8080 register pairs push d ; push b ; lhld ry ;pointer to end of buffer xchg ;place in DE lhld rx ;pointer to current byte call seq ;skip if equal jmp di5 ;still have bytes in the buffer mvi c,20 ; lxi d,tfcb ;file control block call bdos ; lxi h,tbuf+tsiz ;end of buffer shld ry ;store it in ry lxi h,tbuf ;beginning of buffer shld rx ;store it in rx di5: mov a,m ;common continuation inx h ;byte in acc, advance pointer shld rx ;store position of next byte pop b ;replace 3 register pairs pop d ; pop h ; ret ; Stack the secondary file name on the 8080's PDL. pualt: mvi b,fsiz ;load size of file name lxi d,talt ;load origin of secondary name pop h ;put the return address in HL pual: ldax d ;load acc from FCB push psw ;transfer to 8080 stack inx d ;advance pointer dcr b ;reduce count jnz pual ;repeat until count vanishes pchl ;return to addr stored in HL ; ================ ; = main program = ; ================ main:: lhld emem ;BDOS entry point is end of memory sphl ;define stack (end of memory) lxi d,-800H ;reserve space for stack dad d ; mvi m,0 ;0000 as barrier for '>' dcx h ; mvi m,0 ; dcx h ; shld p4 ;end of workspace xchg ; lxi h,bmem ;beginning of free memory shld c0 ;compile area lower limit shld c1 ;compile area pointer mov a,e ;calculate amount of available memory sub l ; mov e,a ; mov a,d ; sbb h ; mov d,a ; mvi b,3 ;right shift 3 = divide by 8 majn: mov a,d ;shift loop ora a ; rar ; mov d,a ; mov a,e ; rar ; mov e,a ; dcr b ; jnz majn ; dad d ;assign 1/2 memory to compile area dad d ; dad d ; dad d ; shld c2 ;compile area upper limit mvi m,0 ;store 0000 as barrier to 'L' inx h ; mvi m,0 ; inx h ; shld px ;beginning of PDL shld py ;with null argument dad d ;assign 3/8 of memory to PDL dad d ; dad d ; shld pz ;upper limit of PDL shld p0 ;lower limit of workspace shld p1 ;initially filled with null text shld p2 ;workspace gets 1/8+roundoff of memory shld p3 ; ; Up to this point the memory has been partitioned between the ; compile area, pushdown list, workspace, and 8080 stack. By ; changing the distribution, it might be possible to accomodate ; the memory balance of a specific application better. lxi d,0003H ;length of one jump instruction lhld bios ;BIOS vector reference point dad d ; shld cnst ;jump to const = bios(1) dad d ; shld cnin ;jump to conin = bios(2) dad d ; shld cnou ;jmp to conout = bios(3) lda tfcb+1 ;if no disk, source from console cpi ' ' ; jz tylo ;type logo - including version date call pualt ;save secondary file name call cpin ;open disk file for REC program lxi h,dire ;REC input through disk shld re ;REC compiler's I-O linkage call inre ;initialize REC compiler RAM call emcx ;compile the program file mvi b,fsiz ;length of filename lxi d,tfcb+fsiz ;end of secondary filename pop h ;emcx leaves execution addr on stack poal: dcx d ;restoration loop runs backward pop psw ; stax d ; dcr b ; jnz poal ; push h ;put execution address back on stack call emcu ;execute the program file jmp boot ;return to CP/M if false jmp boot ;or even if it was true tylo: mvi c,9 ;(09) write message lxi d,logo ;'UAP ...' logo, version date call bdos ; nodi: call bure ;initialize for console buffer call inre ;initialize REC's RAM area call emcx ;compile a program call emcu ;execute it jmp nodi ;no-disk loop jmp nodi ;no-disk loop ; (C) REC compiling operator, which obtains the object code ; origin and the source code address from the pushdown list, ; in the form <'object', 'source', C>. ; ; <'', 'source', C> will use the current value of c1 for the ; object code origin, and would be the alternative normally ; selected by someone who did not want to do his own memory ; management. If c0 .LE. 'object' .LE. c2, c1 will be set to ; 'object', very likely disrupting the compile area; thus any ; origin must be specified with care. However, if the origin ; is taken from a value returned by C, all will work smoothly, ; allowing for the automatic erasure of a subroutine once it ; has been executed and is no longer needed. Likewise there ; will be no conflict if a compile area is taken from the ; pushdown list using the operator c. ; ; Ignoring 'object' for the moment, the various options for ; just <'source', C> are: ; ; ''C input program from console ; 'file' 'D' C take from disk D ; pC pushdown list ; qC workspace ; memory from address org onward ; ; In general, if the 'source' argument is of length zero, then ; the console is the source, while if it is of length one the ; named disk is the source [@=current disk, A, B, ... up to the ; system's limit], and finally if the argument has length 2, the ; combination of from the memory applies. It is the ; programmer's responsibility to avoid nonexistent memory, disk ; units, and the like. ; ; Two values are returned to the pushdown list by C, namely ; <'end', 'origin'>, which define the memory occupied by the ; subroutine just compiled, and which will be needed for the ; subsequent usage of the subroutine. For example, a series ; of subroutines can be compiled by using the 'end' of one as ; 'object' for the next: <'org' 'S1' Cm 'S2' Cm ...> leaving ; their execution addresses on the complementary pushdown list, ; where they may be recovered by the operator n. In practice, ; they would probably be defined as they were compiled using ; <... C 'X'$S ... @X>, or perhaps they would be executed and ; discarded using <... CxL>. Housekeeping is important when ; subroutines are to be discarded during program execution. ; If the origin of a subroutine is saved, it may be reused ; which implies that the space which it and any following ; subroutines occupied may also be reused. ucc: call psiz ;fetch size of top argument mov a,c ;test for zero bytes ora b ;by jamming BC into accumulator jz uc2 ;zero means console dcx b ;test for one byte mov a,c ;by jamming BC into accumulator ora b ; jz uc1 ;one means disk designation dcx b ;verify that we've got two bytes mov a,c ;again jamming BC into A ora b ; jnz rer ;no provision for other than 1, 2 bytes lxi h,pty ;setup readin from pseudoteletype shld re ;REC compiler's I-O linkage call bcld ;size into BC mov e,m ;HL is uncovered px inx h ; mov d,m ; xchg ; shld rx ;origin of REC source code dad b ;length of source code shld ry ;end of source code jmp uc4 uc1: call diin ;setup the CP/M FCB for given file lxi h,dire ;setup input from disk reader jmp uc3 uc2: lxi h,chin ;input from the console uc3: shld re ;REC compiler's I-O linkage uc4: call ucl ;expose 'object program origin' call psiz ;zero or two bytes mov a,c ;check which ora b ; jnz uc5 ;not zero may be two lhld c1 ;compile area pointer xchg ; jmp uc6 ;use compile pointer - no checks needed uc5: dcx b ;verify two dcx b ; mov a,c ; ora b ; jnz rer ;reject anything else call deld ;fetch origin into DE lhld c0 ;compile area lower limit mov a,e ;does it lie in compile area? sub l ; mov a,d ; sbb h ; jc uc6 ;no, it's below c0 lhld c2 ;compile area upper limit mov a,l ; sub e ; mov a,h ; sbb d ; jc uc6 ;no, it's above c2 xchg ; shld c1 ;readjust compile area pointer xchg ; uc6: push d ;execution address call left ;move up to source code call recrr ;compile the source code push d ;byte following compiled subroutine call putw ;word from 8080 stack to PDL call putw ;word from 8080 stack to PDL ret ;must be , not ; (x) Call a subroutine. <'XXXX'Hx> calls the subroutine at ; the absolute location XXXX, which will be assumed to be a ; REC predicate. If it is not, it will act as though it were ; a FALSE predicate, so write ('XXXX'Hx;;) instead, or use (x). go: lhld px ;pointer to top argument call onel ;move from PDL to 8080 stack ret ;must be , not ; ------------------------------------------------------- ; Equivalences to subroutines in the REC nucleus. ; ------------------------------------------------------- ext reclp,recrp,recco,recsc ext recop,recpr,reco1,recp1 ext recdd,recms,recsq,recdq,reccm ; ------------------------------------------------------- ; Equivalences to subroutines outside this overlay. ; ------------------------------------------------------- ext qu,nu,ns,hs ext eql,pe ext ga,gb,gbi,gwi ext sa,sai ext gxs,lcq,ind ext uco,he,hx ext blok,conc ext sum,dif,mpy,dvd ext decr,incr ext exch,comp ext lca,uca,lcb,ucb,ucd,lce,uce,lcf,ucf ext uci,lcj,ucj,lcl,lcm,ucm,ucn,lcn,ucp ext lcq,ucq,lcs,ucu,ucv,lcw,ucy,lcz,ucz ext qm,bra,ket,ip ext vble,libr ext lbr ft: dw noop ;blank dw noop dw recop ; ! binary to hex string dw hx dw recdq ; " quoted expression dw qu dw recop ; # binary to decimal string dw ns dw recop ; $ fetch a variable cell dw vble dw recop ; % restrict to one byte dw pe dw recop ; & exchange top numeric pair dw exch dw recsq ; ' quoted expression dw qu dw reclp ; ( dw noop dw recrp ; ) dw noop dw recop ; * multiply dw mpy dw recop ; + add dw sum dw noop ; , separator like space dw noop dw recms ; - subtract dw dif dw recop ; . dw noop dw recop ; / divide [remainder, quotient] dw dvd dw recdd ; 0 number dw nu dw recdd ; 1 number dw nu dw recdd ; 2 number dw nu dw recdd ; 3 number dw nu dw recdd ; 4 number dw nu dw recdd ; 5 number dw nu dw recdd ; 6 number dw nu dw recdd ; 7 number dw nu dw recdd ; 8 number dw nu dw recdd ; 9 number dw nu dw recco ; : dw noop dw recsc ; ; dw noop dw recop ; < restrict workspace dw bra dw recpr ; = test equality of top pair dw eql dw recop ; > open workspace dw ket dw recpr ; ? test for error report dw qm dw recp1 ; @ execute subroutine dw ar dw recpr ; A advance pointer 1 dw uca dw recpr ; B retract pointer 1 dw ucb dw recop ; C compile dw ucc dw recop ; D delete text dw ucd dw recpr ; E equality between WS and PD dw uce dw recpr ; F find specified text dw ucf dw recop ; G fetch a block from memory dw ga dw recpr ; H ASCII hex to binary dw he dw recop ; I insert dw uci dw recop ; J jump to front dw ucj dw recop ; K call CP/M, keep DE, put value dw cpm dw recop ; L erase top of PDL dw ucl dw recpr ; M compare PDL and workspace dw ucm dw recpr ; N ;numerical comparison on PDL dw ucn dw recpr ; O decimal ASCII string to binary dw uco dw recop ; P put block into buffered memory dw ucp dw recop ; Q put workspace segment on PD dw ucq dw recop ; R read from keyboard dw ucr dw recop ; S store block in memory dw sa dw recop ; T write on screen dw uct dw recpr ; U search, yielding interval dw ucu dw recpr ; V U, including endpoints dw ucv dw recop ; W write on printer dw ucw dw recop ; X call library subroutine dw libr dw recpr ; Y recover previous position of p1 dw ucy dw recop ; Z pointer 2 to end of text dw ucz dw reccm ; [ comment dw noop dw recop ; \ insert single byte in pair dw ip dw recop ; ] dw noop dw recop ; ^ increment top argument dw incr dw recop ; _ exit to monitor dw boot dw recpr ; ` true for waiting character dw chaw dw recpr ; a segment forward from p1 dw lca dw recpr ; b segment backward from p2 dw lcb dw recop ; c create block on PDL dw blok dw recpr ; d decrement but skip on zero dw decr dw recpr ; e extend workspace dw lce dw recpr ; f block fill dw lcf dw recop ; g non-incrementing byte fetch dw gb dw recop ; h dw noop dw recop ; i input from designated port dw lci dw recop ; j null interval at p1 dw lcj dw recop ; k call CP/M: no returned values dw cpml dw recop ; l put pz on PDL dw lcl dw recop ; m set aside top argument dw lcm dw recop ; n recover set-aside argument dw lcn dw recop ; o output from designated port dw lco dw recop ; p put px, py-px on PDL dw gxs dw recop ; q put p1, p2-p1 on PDL dw lcq dw recop ; r indirect replacement of address dw ind dw recop ; s store block in memory wrt limit dw lcs dw recop ; t type out indicated interval dw lct dw recop ; u incrementing byte fetch dw gbi dw recop ; v incrementing byte store dw sai dw recop ; w store workspace header dw lcw dw recpr ; x subroutine call - no arguments dw go dw recop ; y fetch byte pair to PDL incr org dw gwi dw recop ; z null interval at p2 dw lcz dw lbr ; { ;start a definition string dw noop dw recop ; | concatinate top two arguments dw conc dw noop ; } end of definition set dw noop dw recop ; ~ complement or negate top arg dw comp dw recop ; del dw noop ; ----------------------------------------------------- ; RAM memory which is required for the operation of REC ; ----------------------------------------------------- ; Relay area for input and output subroutines. const: db (jmp) cnst: dw 0000H conin: db (jmp) cnin: dw 0000H conou: db (jmp) cnou: dw 0000H read:: db (jmp) ;character input for REC compiler re:: dw chin tyin:: db (jmp) ;single character input for R ti:: dw chin tyou:: db (jmp) ;single character output for T to:: dw chou ; Temporary storage used by the REC compiler. xpd:: dw 0000 ;colon jump back to left parenthesis ypd:: dw 0000 ;false predicate jump chain zpd:: dw 0000 ;semicolon exit chain ; Pointers to the directories. fxt:: dw ft ;pointer to fixed operator directory vrt:: dw vt ;pointer to subroutine directory ; Pointers to the area of compiled subroutines. c0:: dw 0000H ;beginning of compiling area c1:: dw 0000H ;beginning of present compilation c2:: dw 0000H ;final location of present compilation ; Pointers to REC/MARKOV pushdown list. px:: dw 0000H ;beginning of pushdown text py:: dw 0000H ;end of pushdown text pz:: dw 0000H ;end of available pushdown space ; Workspace pointers. p0:: dw 0000H ;beginning of workspace p1:: dw 0000H ;beginning of marked segment p2:: dw 0000H ;end of marked segment p3:: dw 0000H ;end of text p4:: dw 0000H ;end of workspace ; I-O pointers. rx:: dw 0000 ry:: dw 0000 ; Linkage to input-output through ports. qin:: db (in) qi:: db 00H ret qou:: db (out) qo:: db 00H ret ; Temporary storage. pt:: dw 0000 ; Error flag. er:: dw 0000 vt: ds 100H ;directory for programs compiled by REC bmem: ds 0 ;end of REC, begin free memory. end main