;STATES3 12/05/80 ;XYBASIC Interpreter Source Module ;Copyright (C) 1978, 1979, 1980 by Mark Williams Company, Chicago ;statement routines for statements ON through WAIT ;ON {GOTO | GOSUB} [, ]* on: call gtexp ;value to BC call gtcha cpi gotot jz ongot cpi gsubt jnz snerr ;SN error if not GOTO or GOSUB stc ongot: push psw ;carry set for GOSUB, reset for GOTO dcx b ;value - 1 to BC mov a,b ora a inx b cnz on3 ;count negative or big on1: call gtlno ;line # to DE dcr c ;decrement count jz on2 ;do current line # call gtcom ;look for comma jnc on1 ;keep going call onerr ;nonfatal ON error if line # list exhausted on2: call gtdel ;scan to end of statement call goto2 ;set TEXTP and LNNUM pop psw rnc ;done if GOTO jmp gosu1 ;else build GOSUB control stack entry on3: mvi c,1 jm onerr ;replace negative values by 1 mvi c,255 ;and positive by 255 onerr: error n, O, N ;nonfatal ON error ret ;and return ;OUT , if not wild put: call gtbex ;get byte expression mov a,c sta wport + 1 ;set port # call gtcbe ;get comma, byte expr mov a,c jmp wport ;OUT it and return endif ;end of NOT WILD conditional if epstn ;PLOT [, ]* plot: lda colum ;find current column push psw ;and save plot1: xra a sta colum ;clear column count call gtbex ;get byte valued expr mov a,c call writc ;write the char call gtcom ;look for comma jnc plot1 ;more pop psw sta colum ;restore column count ret endif ;POKE , if not wild poke: call gtexp push b ;save location call gtcbe ;get comma, byte expr mov a,c pop b stax b ;store data in location ret endif ;end of NOT WILD conditional ;{PRINT | ?} [@] [[] {, | ;}]* [] ; ::= [UNS | TAB | SPC] | | ;PRINT first PUSHes a return to itself, so the print routines may be CALLed ;and simply RETurn. The routines for comma and semicolon check for following ;delimiter, so a delimiter found after any other item produces a crlf. ;DPRIN is in module SDISK. ;WILD PRINT is in module WILD, and calls PRIN0. if not wild print: if sdisk call gtsfn ;look for file number jnc dprin ;PRINT to file endif endif prin0: lxi b,prin0 push b ;push common return to print more call gtcho ;look at next char cpi '"' ;look for quoted string first to avoid eval jz prqu0 ;quoted string if camac cpi drivt jz prdri ;print DRIVER call gtcam ;look for camvar name jnc prcam ;print the camvar value endif call eval ;look for expression jnc prval ;expression found, print its value call dtest jz prdel ;delimiter, print crlf and exit if not wild ;only one print item allowed in WILD versions call read1 ;read the char cpi ',' jz prcom ;comma cpi semic jz prsem ;semicolon cpi tabt jz prtab ;TAB if not camac cpi spct jz prspc ;SPC endif if not float ;UNS allowed as print fn in nonfloat versions cpi unst jz pruns endif if not strng ;CHR$ allowed as print fn in nonstring versions cpi chrst jz prchr endif endif ;end of NOT WILD conditional jmp snerr ;else SN error ;print delimiter prdel: pop b ;pop the PRINT return jmp wcrlf ;write crlf and exit ;print the value of an EVALuated expression prval: call fetc1 ;fetch the value iftyp prsng,prstr ;branch if noninteger prinv: mov a,b ora a ;check sign of integer value jp priv1 ;print unsigned if positive if wild jmp wrtbs else call wrtbs ;otherwise write signed jmp wrts0 ;write trailing space and return endif priv1: mvi a,' ' ;leading space to A if wild jmp wrtb1 else call wrtb1 ;write unsigned with leading space jmp wrts0 ;write trailing space and return endif if not wild ;comma, space to the next tab stop prcom: call prco1 ;do the comma ;and fall through to PRSEM for delimiter test ;semicolon prsem: call dtst0 ;check if next char is delimiter rc ;nondelimiter, continue printing pop b ;else pop the PRINT return ret ;and exit from PRINT prco1: lhld colum mov a,l ;fetch current column ora a rz if float ;comma column width is 14 if floating lxi b,14 ;comma column width to BC mov l,b ;0 to L jp prco2 ;column is < 128 currently mvi l,126 ;else make L 14*9 sub l ;and reduce column accordingly prco2: dad b ;add comma width sub c ;subtract comma width from column jp prco2 ;repeat until negative else ;comma column width is 8 if nonfloating ori 7 inr a ;compute desired column mov l,a ;save column in L endif mov a,h ora a mov a,l ;fetch desired column jz prco3 ;width 0, suppress cr check cmp h ;compare to width jnc wcrlf ;write crlf if >= width prco3: mov c,a jmp prta1 ;else tab to column desired ;UNS if not float pruns: call gtexp ;get argument jmp priv1 endif ;TAB prtab: call prta0 ;get arg mod width prta1: lda colum cmp c rz ;found desired column call prta2 ;else write spaces until there jmp prta1 prta2: jc wrtsp ;write a space if left of desired column jmp wcrlf ;else write a crlf ;PRTA0 evaluates mod width for TAB and SPC prta0: call gtexp ;get argument lda width ora a ;Zero set iff width 0 mov e,a mvi d,0 push d cnz opmod ;evaluate arg mod width unless width 0 pop d ;restore width to DE mov a,b ora a ;check if arg was negative cm iadd ;yes, add width to result to make positive ret ;SPC if not camac prspc: call prta0 ;get arg mod width mov a,c ora a prsp1: rz ;done call wrtsp ;else write a space dcr c ;decrement space count jmp prsp1 ;and repeat endif endif ;end of NOT WILD condtional ;quoted string prqu0: call read1 ;read the " prquo: mov d,h mov e,l ;address of first char to DE call gtclq ;scan to close quote or cr mov a,l ;fetch last+1 address sub e ;last+1 - first = # chars prst0: mov c,a ;to C jmp prstr ;and print the string if not strng ;allow CHR$ as print fn prchr: call gtbex ;get byte-value expr mov a,c jmp writc ;write value and return endif ;floating point value if float prsng: call fout ;convert FACC to string if wild jmp prstl else call prstl ;write the string jmp wrts0 ;write trailing space and return endif endif ;PRCAM is in module CAMAC. ;RANDOMIZE if not wild rndiz: call gtexp mov h,b mov l,c ;value to HL shld randx ;and it becomes new seed ret endif ;end of NOT WILD conditional ;READ ;READ must scan the command line READ and lines of DATA [,]*. ;The text pointers are kept in TEXTP and TXTP2 and exchanged by FLIP. read: lhld rdptr shld txtp2 ;READ pointer to TXTP2 reada: call gtlhs ;get destination for ASSGN if strng push psw ;save var type in string version endif call flip ;to scan data call gtcnd ;see if comma (in DATA ,...) next cc reade ;no, find next DATA statement if strng pop psw ;restore var type cpi strst jnz readb ;not a string var call evunq ;string var, get value (possibly unquoted) jmp readd endif readb: call gtlit ;look for value jc readf ;no value found readd: call asigv ;assign value to variable call flip ;to scan varlist call gtcom ;look for comma jnc reada ;read another lhld txtp2 ;else recover new RDPTR shld rdptr ;and store it ret ;and done ;READE finds the next DATA statement. ;Issues nonfatal OD error and retries if no more DATA. ;Issues fatal SN error if SN error in DATA. reade: call dtst0 ;check if at delimiter jc readf ;no -- SN error in DATA mvi b,datat call fndst ;find next DATA rnc ;OK if found error n, O, D ;nonfatal OD error call rstor ;do a RESTORE shld textp jmp reade ;and try again ;READF issues fatal SN error for bad DATA items. readf: xchg ;DATA textp to DE call fndln ;find its line number shld lnnum ;reset line # for error message error f, S, N ;fatal SN error ;REM rem: call gtcha cpi cr jnz rem ;scan to call bakup ;back up text pointer inx h ;let HL point to next byte in case on-line ret ;RENUM [ [, [, ]]] if editc if compl renum equ uferr else ;RENU0 gets an optional comma followed by , default value from DE. renu0: call gtcnd ;look for comma cnc gtlno ;if comma look for xchg ;to HL ret ;and return ;First RENUM must get arguments. ;RNOLD gets the old line # of first renumbered line, ;RNNEW gets the new line # of first renumbered line, and ;RNINC gets the renumbering increment. renum: if romsq call issrc ;must be addressing working space endif call gtlno ;look for jnc renu1 ; given call findl ;none given -- look for line 0 stc ;to skip following FDLNO renu1: cnc fdlno ;find the specified line # push h ;save first renumbered line location call modem ;line # of first renumbered line to DE push d ;and saved xchg shld rnold ;and saved in RNOLD lxi d,10 ;default arg2 is 10 call renu0 ;get increment mov a,h ora l jz userr ;fatal US error if 0 (e.g., RENUM 10,,) shld rninc ;increment saved in RNINC xthl ;save increment, first line line # to HL xchg ;and then to DE as default arg3 call renu0 ;get destination shld rnnew ;and saved in RNNEW xchg ;destination to DE call iitst ;RENUM illegal indirect ;Now test if the specified args give too large a max . pop b ;increment to BC pop h ;location to HL push b push d push h ;save args mov a,m ;fetch length call adahl ;address second line renu2: mov a,m ;fetch length ora a jz renu3 ;eof call adahl ;address next line xchg dad b ;compute its eventual line # xchg jnc renu2 ;continue if no overflow jmp userr ;too large, US error ;Now test if last line # before first is < new first. renu3: lxi b,0 ;last line before first initially 0 pop d ;first line # length byte address to DE lxi h,srcad ;start at beginning of source text renu4: call cmdhu ;compare first to current jz renu5 ;matched, BC now has last inx h mov c,m inx h mov b,m ;line number to BC dcx h dcx h mov a,m ;fetch length byte call adahl ;address next jmp renu4 ;and try it renu5: pop d ;new first line # to DE push d ;and resave call cmbdu ;compare to line # before first jnc userr ;US error if previous is larger lhld textp push h ;save TEXTP call lnref ;change references in source text pop h shld textp ;Now change the actual s. lhld rnold xchg ;RNOLD to DE call findl ;find (possibly new) location of first changed pop d ;RNNEW to DE pop b ;RNINC to BC renu6: mov a,m ;fetch length of next line ora a jz renu7 ;all line numbers changed push h ;save current length byte address call adahl ;address next line xthl ;save next, recover current inx h mov m,e inx h mov m,d ;change the line number pop h ;next line length byte address to HL xchg dad b xchg ;update line number jmp renu6 ;and renumber more ;Check break bytes for flag indicating illegal in line. renu7: mvi b,0 ;clear bad line flag lxi h,srcad ;begin at the beginning renu8: mov a,m ora a jz renux ;eof, done push h ;save length byte loc inx h inx h ;skip line # bytes inx h ;and address break byte mov a,m ;fetch it ora a ;check bit 7 jp renu9 ;ok if not set dcx h dcx h ;address line # byte call prntl ;print the bad line call wcrlf ;and crlf mvi b,255 ;and set bad line flag renu9: pop h mov a,m ;refetch length call adahl ;address next line jmp renu8 ;and try next line renux: push b ;save bad line flag call addl3 ;text may have moved, reset stacks pop psw ;recover bad line flag ora a rz ;successful RENUM jmp userr ;else US error message endif else renum equ exerr ;EX error in non-EDITC versions endif ;RESTORE [] restr: call gtlno ;look for line # jc rstor ;none, take least call fdlno ;find the line jmp rsto1 ;and reset the read pointer rstor: if romsq lhld sourc else lxi h,srcad endif rsto1: dcx h ;point to preceding line shld rdptr ;let read pointer address ret ;RETURN retrn: call eos ;end of statement test lxi b,(csgos shl 8) or csint call csdig ;look for gosub or interrupt cstack entry jc rgerr ;not found -- RG error call cspop ;pop cstack information cmp b ;zero set if gosub, reset interrupt jz csrst ;GOSUB entry -- reset stack & return push psw call mvdem ;interrupt table byte addr to DE ldax d ori 40H ;resume interrupt stax d pop psw jmp csrst ;reset control stack and return rgerr: error f, R, G ;fatal RG error ;RUN [] if compl run equ uferr ;UF error if COMPL version else run: if sdisk call closn ;close any OPEN files endif if camac and false ;Northstar version call close ;close any OPEN files endif call gtlno ;look for line # push psw push d call iitst ;RUN illegal indirect call clea1 ;clear CSTACK, symbol table, string space if not wild call disab ;disable interrupts endif call rstor ;restore READ pointer pop d pop psw jnc goto2 ;line # specified, execute from there shld textp ;else point to before source text ret ;and execute from there endif ;SAVE is in section STATES4. ;SCALL [, ]* ;SCALL loads BC, DE and HL with the values of the s, if any, ;and branches to the address. When the user routine RETurns, ;the values in BC, DE and HL are assigned to the s. scall: call gtexp lhld textp shld savtp ;save textp for rescan on return lxi h,sretn push h ;return address to stack push b ;branch address to stack lxi d,3 ;maximum parameter count to DE scal1: call gtcnd ;look for comma not followed by delimiter jc scal2 ;none, set up registers and branch to user call gtiva ;perform integer var ref jc mcerr ;not a var ref push b ;save parameter value dcr e ;decrement parameter count jnz scal1 ;get more parameters if not three already call gtcnd ;check if more parameters jc scal2 ;no more error n, M, C ;nonfatal MC error if too many ;At SCAL2, DE contains 3 - # parameters specified, and the parameter values ;are PUSHed. By adding DE to the address POP3, the branch address ;is computed to POP 3, 2, 1 or 0 values before branching to the user routine. scal2: lxi h,pop3 dad d ;compute pop address pchl ;branch to it ;SRETN is the entry point from the user routine's RETurn. sretn: push h push d push b ;save registers lhld savtp shld textp ;restore TEXTP lxi d,0 ;# of POPed registers to DE sret1: call gtcnd ;look for comma jc scal2 ;done, POP extras and return inr e ;increment POPed count mvi a,3 cmp e jc nextc ;too many, scan to end and return push d call gtlhs ;get destination inx h ;point to high order destination pop d pop b ;value to BC call asigi ;assign integer value, traced jmp sret1 ;and repeat ;SETTIME [, ] [, ] if realt and not camac ;SETTIME in REALT versions only sttim: lxi h,timex+3 ;HL addresses hour count lxi d,24 ;max # hours ora a ;reset Carry call stti2 ;get hours count and set clock lxi d,60 ;max # minutes or seconds call stti1 ;get minutes count and set clock call stti1 ;get seconds count and set clock dcx h mvi m,255 and -20 ;reset 20ths count ret stti1: dcx h ;point to next time component push h call gtcnd ;look for comma pop h lxi b,0 ;default to 0 if unspecified stti2: cnc gtexp ;get desired count call cmbdu ;compare to max cnc fcer0 ;too big, nonfatal FC error and return 0 mov a,c ;fetch count sub e ;subtract bias mov m,a ;and store to set clock ret endif ;STOP if compl ;STOP boots in COMPL version if wild stop equ uferr ;UF error in WILD RTPAK else stop equ boot endif else stop: mvi a,csbrk ;break token to A stop1: push psw ;line break entry point call linbc ;line # to BC jz dmod2 ;direct mode -- do not save info call prtm0 ;turn on OMODE, print BREAK message db cr, lf, 'BREAK AT LINE', ' ' or 80H call wrtbu ;print line # unsigned pop psw stop2: call cpush ;break info to control stack -- END entry point jmp dmod2 ;and continue in DMODE endif ;end of COMPL conditional ;TIME if (not camac) and (not realt) time: mvi a,cntlg call writc ;ring a bell lxi h,0 call readc ;get and ignore first char call timer jnc exerr ;counted to 0 -- EX error call ctest ;read the char TIMER saw push h ;save minute count mov a,h sta timex+4 ;minute count / 256 to TIMEX+4 mov b,h mov c,l lxi d,60 call divd0 ;min count / 60 = sec count to HL pop d call cplde ;complement minute count xchg shld timex ;complmented minute count to TIMEX call cplde ;complement second count xchg shld timex+2 ;complemented second count to TIMEX+2 ret endif ;TRACE | UNTRACE ;TRAP | UNTRAP if compl tcon equ uferr ;UF error if COMPL version tcoff equ uferr tpon equ uferr tpoff equ uferr else tcon: stc tcoff: sbb a ;A gets 0 if no carry, 255 if carry sta trace ret tpoff: stc tpon: sbb a sta trap ret endif ;end of NOT COMPL conditional ;UNBREAK [ | ] ;UNBREAK removes all breakpoints. ;UNBREAK removes the breakpoint (if any) on the specified line. ;UNBREAK removes breakpoints on the specified variables. if compl unbrk equ uferr ;UF error if COMPL version else unbrk: call gtlno ;see if line # present jc unbr2 ;no ;Remove breakpoint from line # in DE. if romsq call isrom ;must be running in RAM endif call fdlno ;find the line ;UNBR1 removes the breakpoint on line addressed by HL. unbr1: inx h ;move pointer from length byte inx h ; past line # inx h ; to break byte mvi m,0 ;and zero it ret unbr2: call dtest ;see if var list present jc ubvar ;yes lhld symta ;no, unbreak all lines and variables ;UNBR3 removes all variable breakpoints. unbr3: call stnxt ;get next symbol table entry jc unbkl ;end of table -- unbreak lines and return ldax d ani 7FH stax d ;unbreak one entry jmp unbr3 ;UBVAR removes breakpoints on the specified variables. ubvar: call fdvar ;find var ref jc snerr ldax d ani 7FH stax d ;unbreak it call gtcnd ;look for comma jnc ubvar ;unbreak another var ret endif ;end of NOT COMPL conditional ;UNTRACE and UNTRAP are under TRACE and TRAP above. ;WAIT , [, ] [,$] if not wild wait: call iinfo ;get interrupt info mov a,c ral ral mov c,a ;$ bit to C7 mov a,b ;port # to A call rdp1 ;read ora e ;mask xra d ;compare jz wait1 stc ;carry set iff compare nonzero wait1: rar ;A7 set iff compare nonzero xra c ;sign set iff keep waiting rp ;condition fulfilled -- return lhld savtp shld textp ;reset text pointer to parse WAIT again ret endif ;end of NOT WILD conditional ;end of STATES3 page