; ; PROGRAM: DPROG ; AUTHOR: Richard Conn ; VERSION: 1.0 ; DATE: 28 July 84 ; PREVIOUS VERSIONS: None ; vers equ 10 z3env equ 0f400h ; ; DPROG is used to program the user's terminal, printer, or punch ; with data from the file specified in the command line. DPROG will ; automatically search for the file along the path starting at the ; indicated (or implied) DU. ; ; ; Basic Equates ; opsys equ 0 fcb equ 5ch tbuff equ 80h cr equ 0dh ff equ 0ch lf equ 0ah ctrlc equ 'C'-'@' ctrls equ 'S'-'@' ctrlz equ 'Z'-'@' bel equ 7 bs equ 8 tab equ 9 ; ; DPROG Constants ; COMMENT equ ';' ;denotes a comment line WORD equ '-' ;denotes a word definition SYM equ '=' ;symbol table dump command DEV equ '>' ;device assignment INP equ '<' ;input forms (pause, string, delay) wordl equ 16 ;length of word fmt equ '(' ;begin format definition fmtch equ '%' ;format escape char endfmt equ ')' ;end format definition quote equ '"' ;quote string literal equ '\' ;literal interpretation follows control equ '^' ;control char follows ; ; SYSLIB Routines ; ext condin,cin,cout,lout,pout ext z3init,pfind,z3log ext moveb,hmovb,logud,pfn1,caps ext f$open,f$read,f$close ext eval,pafdc,pa2hc ext codend ; ; Environment Definition ; if z3env ne 0 ; ; External ZCPR3 Environment Descriptor ; jmp start db 'Z3ENV' ;This is a ZCPR3 Utility db 1 ;External Environment Descriptor z3eadr: dw z3env start: lhld z3eadr ;pt to ZCPR3 environment ; else ; ; Internal ZCPR3 Environment Descriptor ; MACLIB Z3BASE.LIB MACLIB SYSENV.LIB z3eadr: jmp start SYSENV start: lxi h,z3eadr ;pt to ZCPR3 environment endif ; ; Start of Program -- Initialize ZCPR3 Environment ; call z3init ;initialize the ZCPR3 Env ; ; Initial Routines ; call helpck ;check for help call bufinit ;initialize buffers ; ; Load File ; call locfile ;locate file call logud ;enter directory of file call load ;load file ; ; Perform Program ; call program ;program the user's terminal ret ; ; Initialize Buffers ; bufinit: call codend ;address of free space shld format ;format string xchg lxi h,deffmt ;set default format (char) mvi b,40 ;allow 40 chars call moveb xchg ;HL pts to format buffer inr h ;next page shld locstk ;set location stack shld tos ;set top of stack mvi m,0 inx h mvi m,0 ;zero stack dcx h inr h ;next page shld free ;free area mvi a,'C' ;assign console as output device sta outdev ret ; ; Check for Help ; helpck: lxi h,fcb+1 ;pt to fcb name mov a,m ;get it cpi '/' ;help if slash rnz pop psw ;clear stack call eprint db 'DPROG, Version ' db (vers/10)+'0','.',(vers mod 10)+'0' db cr,lf,' Syntax:' db cr,lf,' DPROG <-- STD.DPG' db cr,lf,' DPROG filename <-- filename.DPG' db cr,lf,' DPROG filename.typ <-- filename.typ' db 0 ret ; ; Find File ; If found, return BC=DU and NZ ; locfile: lxi d,fcb ;pt to FCB call z3log lxi d,fcb+1 ;pt to file name lxi h,defname ;pt to default file name mvi b,8 ;8 chars ldax d ;any type? cpi ' ' ;none if space cz moveb lxi d,fcb+9 ;pt to file type lxi h,deftype ;pt to default file type mvi b,3 ;3 chars ldax d ;any type? cpi ' ' ;none if space cz moveb lxi d,fcb ;pt to FCB mvi a,0ffh ;search current call pfind ;search for file rnz ;get file if found ; ; Abort Attempt to Load File ; abort: pop psw ;clear stack call eprint db cr,lf,' File ',0 lxi d,fcb+1 ;pt to file name call pfn1 call eprint db ' NOT Found',0 ret ; ; Load File ; load: lxi d,fcb ;pt to fcb call f$open ;open file for input jnz abort ;abort attempt lhld free ;buffer area load1: lxi d,fcb ;pt to fcb call f$read ;read next block jnz load2 ;done, so mark and close lxi d,tbuff ;copy into buffer xchg ;copy into buffer at DE from TBUFF at HL mvi b,128 ;128 bytes call moveb lxi h,80h ;pt to next buffer dad d jmp load1 load2: mvi m,ctrlz ;mark EOF inr h ;next page mvi l,0 shld words ;mark beginning of word definition area shld nxtword ;mark next word mvi m,0 ;mark no words jmp f$close ;close input file ; ; Program the User's Terminal ; program: lhld free ;pt to first char prog1: call capa ;capitalize cpi ctrlz ;done? rz cpi CR ;eol? jz skipl cpi WORD ;word definition? jz defword cpi SYM ;symbol table or format definition dump? jz dump cpi DEV ;assign device? jz device cpi INP ;input form? jz input push h ;save HL prog2: call output ;output line at HL call locpop ;pop stack if any jnz prog2 ;continue if any element on stack pop h ;restore HL ; ; Skip to next line ; skipl: mov a,m ;get char call capa ;capitalize cpi CR ;new line? jz skipl1 cpi LF ;new line? jz skipl1 cpi CTRLZ ;EOF? rz inx h ;pt to next jmp skipl skipl1: mov a,m ;get it inx h ;pt to next ani 7fh ;mask cpi CR ;continue? jz skipl1 cpi LF ;continue? jz skipl1 dcx h ;pt to non-eol char jmp prog1 ;continue with next line ; ; Input Form ; input: inx h ;pt to next char call cin ;get any char ani 7fh ;mask cpi ctrlc ;abort? jz opsys jmp skipl ;continue ; ; Assign Device ; device: inx h ;pt to char call capa ;capitalize cpi 'C' ;console? jz setdev cpi 'L' ;list? jz setdev cpi 'P' ;punch? jz setdev push psw call eprint db cr,lf,bel,' Invalid Device Assignment: ',0 pop psw call cout ;print char dcx h ;back up jmp skipl ;continue ; ; Perform assignment ; setdev: sta outdev ;assign jmp skipl ;continue ; ; Define Word ; defword: inx h ;pt to first char of word call bufword ;store word in buffer shld nextch ;save ptr to next char call wscan ;scan for word jz defnew ;new word defined xchg ;ptr to high-order in DE lhld nextch ;get ptr to word definition xchg ;word defn in DE, word adr high in HL mov m,d ;store new address dcx h mov m,e xchg ;HL pts to word jmp skipl ;skip out line ; ; New Word ; defnew: lhld nxtword ;pt to next word xchg lxi h,wordbf ;pt to buffer mvi b,wordl ;number of chars max call hmovb ;copy into buffer and advance HL lhld nextch ;get address xchg mov m,e ;put low inx h mov m,d ;put high inx h ;set ptr to next word mvi m,0 ;store zero shld nxtword ;set ptr xchg ;HL pts to word definition jmp skipl ;skip to next line ; ; Dump Format String or Word Table ; dump: inx h ;pt to option call capa ;check for format display option cpi 'F' ;format? jz dfmt ;dump format if so cpi 'S' ;symbols? jz dsym dcx h ;pt to current call dumpsym ;dump symbols call dumpfmt ;dump format jmp skipl ;continue ; ; Dump Format ; dfmt: call dumpfmt ;do dump jmp skipl ;continue ; ; Dump Words ; dsym: call dumpsym ;do dump jmp skipl ;continue ; ; Dump Words in Symbol Table ; dumpsym: push h ;save HL call eprint db cr,lf,' >> Word Definitions <<',0 lhld words ;dump word table sym1: mov a,m ;get next ora a jz symexit call eprint db cr,lf,' ',0 call prword ;print word mov e,m ;get low inx h mov d,m ;get high inx h ;pt to next word push h ;save ptr call eprint db ' >',0 xchg ;HL pts to word sym2: mov a,m ;get next char cpi CR ;done? jz sym3 cpi TAB ;translate tab to space jnz sym2out mvi a,' ' ;space instead of tab sym2out: call chout inx h jmp sym2 sym3: call eprint db '<',0 pop h ;pt to next word jmp sym1 symexit: pop h ;pt to char ret ; ; Output Format String ; dumpfmt: push h ;save ptr call eprint db cr,lf,' Format: (',0 lhld format ;pt to string call epstr ;print it call eprint db ')',cr,lf,0 pop h ;get ptr ret ; ; Print Word at HL (advance HL) ; prword: mvi b,wordl ;number of chars prw1: mov a,m ;get char call chout inx h dcr b jnz prw1 ret ; ; Routine to Output a Line ; output: call sksp ;skip spaces cpi COMMENT ;done? rz cpi CR ;done? rz cpi LF ;done? rz cpi CTRLZ ;done? rz cpi fmt ;format definition? jz outfmt cpi quote ;chars? jz outch call bufword ;store word in buffer shld nextch ;save ptr to next char after word call wscan ;scan for word in table jz badword ;word not defined call locpush ;push location onto stack xchg ;HL pts to continuation location jmp output ;continue ; ; Output Quoted String ; outch: inx h ;pt to next char outch1: mov a,m ;get it ani 7fh ;mask cpi CR ;done? jz outcherr cpi LF ;done? jz outcherr cpi CTRLZ ;done? jz outcherr cpi quote ;end of quote? jz outch2 call charout ;output char in whatever form jmp outch1 ;continue outcherr: call eprint db cr,lf,bel,' Premature End of Quote',cr,lf,0 jmp output outch2: inx h ;pt to after quote jmp output ;continue ; ; Output char in A and set HL to next char on exit ; charout: cpi control ;control char follows? jz charo0 cpi literal ;literal follows? jz charo1 ; ; Normal Char in A ; charnxt: inx h ;pt to next char jmp formatout ;output with format ; ; Output control char ; charo0: inx h ;pt to char call capa ;get char sui '@' ;convert to control jc ctrlerr cpi 20h jnc ctrlerr inx h ;pt to next jmp formatout ctrlerr: call eprint db cr,lf,bel,' Invalid Control Character',cr,lf,0 ret ; ; Output Literal Format ; charo1: inx h ;pt to char call capa ;get char cpi 'B' ;BS? jz c1bs cpi 'D' ;DEL? jz c1del cpi 'E' ;ESCAPE? jz c1esc cpi 'L' ;CRLF? jz c1nl cpi 'N' ;LF? jz c1lf cpi 'R' ;CR? jz c1cr cpi 'T' ;TAB? jz c1tab cpi '0' ;digit? jc charol ;literal if not cpi '9'+1 ;range? jc numout cpi ' ' ;less than space? jnc charol call eprint db cr,lf,bel,' Invalid Literal Argument',cr,lf,0 ret ; ; Output Char in A literally ; charol: mov a,m ;get char ani 7fh ;don't cap this way inx h ;pt to next jmp formatout ; ; Output Number ; numout: call eval ;convert to binary in DE mov a,e ;char binary value jmp formatout ;output with format ; ; Output BS ; c1bs: mvi a,bs jmp charnxt ; ; Output TAB ; c1tab: mvi a,tab jmp charnxt ; ; Output CR ; c1cr: mvi a,cr jmp charnxt ; ; Output DEL ; c1del: mvi a,7fh jmp charnxt ; ; Output ESCAPE ; c1esc: mvi a,1bh jmp charnxt ; ; Output LF ; c1lf: mvi a,lf jmp charnxt ; ; Output CRLF ; c1nl: mvi a,cr call formatout ;output CR mvi a,lf jmp charnxt ; ; Output Char in A According to Format ; formatout: push h ;save ptr to next char push b ;save BC mov b,a ;char in B lhld format ;pt to format string fout1: mov a,m ;get next char ani 7fh ;mask jz foutx ;exit if end of string cpi fmtch ;expression form? jz fout2 cpi literal ;literal? jz flit ; ; Output char in A and advance ; fch: call chout ;output char inx h ;pt to next jmp fout1 ; ; Output Value in B according to format ; fout2: inx h ;pt to format type mov a,m ;get char inx h ;pt to next ani 7fh ;mask call caps ora a ;none? jz fout1 ;error condition - % at end of string cpi 'C' ;char? jz foch cpi 'D' ;floating decimal chars jz fod cpi '2' ;2 decimal chars jz fo2 cpi '3' ;3 decimal chars jz fo3 cpi 'X' ;2 hex chars jz fox push psw call eprint db cr,lf,bel,' Invalid Format Char: ',0 pop psw call cout call crlf jmp fout1 ;continue ; ; Output value in B as char ; foch: mov a,b ;get value call chout ;output it jmp fout1 ;continue ; ; Output value in B as floating decimal ; fod: mov a,b ;get value call pafdc ;output jmp fout1 ;continue ; ; Output value in B as hex ; fox: mov a,b ;get value call pa2hc ;output jmp fout1 ;continue ; ; Output value in B as 3 decimal chars ; fo3: mvi c,100 ;100's call dec ;output and fall thru to FO2 ; ; Output value in B as 2 decimal chars ; fo2: mvi c,10 ;10's call dec mov a,b ;get value adi '0' ;convert call chout jmp fout1 ;continue ; ; Subtracting Output ; Output value in B as 100's or 10's digit (leading 0 allowed) ; dec: push d ;save DE mov a,b ;get value mvi d,'0' ;set digit dec1: sub c ;subtract jc dec2 inr d ;increment digit jmp dec1 dec2: add c ;add back in mov b,a mov a,d ;output digit call chout pop d ;restore DE ret ; ; Exit Format String Output ; foutx: pop b ;restore BC pop h ;restore ptr to next char ret ; ; Literal Format Output ; flit: inx h ;pt to char call capa ;get char cpi 'B' ;BS? jz f1bs cpi 'D' ;DEL? jz f1del cpi 'E' ;ESCAPE? jz f1esc cpi 'L' ;CRLF? jz f1nl cpi 'N' ;LF? jz f1lf cpi 'R' ;CR? jz f1cr cpi 'T' ;TAB? jz f1tab cpi '0' ;digit? jc fchck ;literal if not cpi '9'+1 ;range? jnc fchck ; ; Output Number ; call eval ;convert to binary in DE mov a,e ;char binary value jmp fch ;output ; ; Check for Valid Literal ; fchck: cpi ' ' ;not valid if less than space jnc fch call eprint db cr,lf,bel,' Invalid Literal Argument',cr,lf,0 jmp fout1 ; ; Output BS ; f1bs: mvi a,bs jmp fch ; ; Output TAB ; f1tab: mvi a,tab jmp fch ; ; Output CR ; f1cr: mvi a,cr jmp fch ; ; Output DEL ; f1del: mvi a,7fh jmp fch ; ; Output ESCAPE ; f1esc: mvi a,1bh jmp fch ; ; Output LF ; f1lf: mvi a,lf jmp fch ; ; Output CRLF ; f1nl: mvi a,cr call chout ;output CR mvi a,lf jmp fch ; ; Define New Output Format ; outfmt: inx h ;pt to format char xchg lhld format ;pt to format area xchg ; ; Get next char for format string ; outf1: mov a,m ;get next char ani 7fh ;mask cpi endfmt ;end of format? jz outf2 cpi CR ;end of line? jz outf3 cpi LF ;end of line? jz outf3 cpi CTRLZ ;end of file? jz outf3 stax d ;store char inx h ;pt to next inx d cpi literal ;literal denotation? jnz outf1 ;continue if not ; ; Literal flag, so store next char exactly as-is without interpretation ; mov a,m ;get next char ani 7fh ;mask stax d ;store it literally inx h ;pt to next inx d jmp outf1 ; ; Format String Stored - Terminate it ; outf2: inx h ;pt to next char outf3: xra a ;terminate format string stax d jmp output ; ; Invalid Word - So State ; badword: call eprint db cr,lf,bel,' Invalid Word Reference: ',0 lxi h,wordbf ;pt to buffer call prword ;print word lhld nextch ;continue jmp output ; ; Element must be a word - resolve it ; bufword: lxi d,wordbf ;buffer to store word in mvi b,wordl ;length ; ; Build Word into WORDBF ; bword1: call capa ;get char cpi ' '+1 ;end? jc bword3 stax d ;store char inx h ;pt to next inx d dcr b ;count down jnz bword1 ; ; Word is longer than WORDL - skip trailing chars ; bword2: mov a,m ;skip chars to delimiter ani 7fh ;mask cpi ' '+1 jc bword4 inx h ;pt to next jmp bword2 ; ; Word is built into WORDBF - space fill it ; bword3: mvi a,' ' ;space stax d ;store char inx d ;pt to next dcr b ;count down jnz bword3 ; ; Word is Stored ; HL pts to next char after the Word ; bword4: ret ; ; Scan for Word in Table ; Return with Zero Set if Not Resolved ; If Resolved, DE=address of word ; wscan: lhld words ;pt to first word in table wscan1: mov a,m ;abort if empty table ora a rz lxi d,wordbf ;pt to buffer mvi b,wordl ;size of buffer push h ;save HL wscan2: ldax d ;get char cmp m ;compare jnz wscan3 inx h ;pt to next inx d dcr b ;count down jnz wscan2 mov e,m ;get address in DE inx h mov d,m pop psw ;clear stack xra a ;return NZ dcr a ret wscan3: pop h ;get address of current word in table lxi d,wordl+2 ;advance to next word dad d jmp wscan1 ; ; Push Address in NEXTCH onto Location Stack ; locpush: push h ;save regs push d lhld nextch ;get address xchg ;... in DE lhld tos ;get top of stack mov m,e ;store address inx h mov m,d inx h shld tos ;new top of stack pop d ;restore regs pop h ret ; ; Pop Address from Top of Stack ; locpop: lhld locstk ;local stack xchg lhld tos ;check to see if nothing on stack mov a,e ;if lows are same, nothing on stack cmp l rz dcx h ;pt to top element mov d,m ;get high dcx h mov e,m ;get low shld tos ;new top of stack xchg ;address in HL xra a ;return with NZ dcr a ret ; ; Skip to Non-Space ; sksp: mov a,m ;get char ani 7fh ;mask call issp ;test for space rnz ;not space, so return inx h ;pt to next jmp sksp ; ; Test char in A for space char ; Ret with Z if yes ; issp: push h ;save HL push b ;save BC lxi h,sptab ;pt to table mov b,a ;char in B issp1: mov a,m ;get next char ora a ;end of table? jz issp3 cmp b ;match? jz issp2 inx h ;pt to next jmp issp1 issp2: mov a,b ;restore char pop b ;restore regs pop h ret ;Z flag is set issp3: xra a ;set NZ dcr a jmp issp2 ; ; Output New Line ; crlf: push psw ;save A mvi a,cr ;CR call chout mvi a,lf ;LF call chout pop psw ;get A ret ; ; Output Char in A with XON/XOFF Flow Control ; chout: push psw ;save char call condin ;conditional input jz chout1 cpi ctrls ;pause? jnz chout1 call cin ;wait for following char chout1: pop psw ;get char push b ;save BC mov c,a ;char in C lda outdev ;get output device cpi 'C' ;console? jz chcon cpi 'L' ;printer? jz chlst cpi 'P' ;punch? jz chpun ; ; Output to Console ; chcon: mov a,c ;get char call cout pop b ret ; ; Output to List ; chlst: mov a,c ;get char call lout pop b ret ; ; Output to Punch ; chpun: mov a,c ;get char call pout pop b ret ; ; Print String Pted to by HL ; epstr: mov a,m ;get char inx h ;pt to next ani 7fh ;mask MSB rz ;done call chout ;print char jmp epstr ; ; Print String at Return Address ; eprint: xthl ;save HL and pt to string call epstr ;print string xthl ;restore HL and new exec adr ret ; ; Input Char, Mask, and Capitalize ; capa: mov a,m ;get char ani 7fh ;mask jmp caps ;capitalize ; ; Space Table ; sptab: db ' ',tab,bs,ff,',','.',0 ;space chars ; ; Data Area ; defname: db 'STD ' ;default file name deftype: db 'DPG' ;default file type deffmt: db '%C',0 ;default format string outdev: ds 1 ;output device (C=console, L=list, P=punch) outdev1: ds 1 ;save area for output device wordbf: ds wordl ;current word buffer format: ds 2 ;address of format string free: ds 2 ;address of free area words: ds 2 ;address of scratch area nxtword: ds 2 ;pointer to next word nextch: ds 2 ;pointer to next char locstk: ds 2 ;pointer to location stack tos: ds 2 ;pointer to top of stack end