.MCALL .MODULE .MODULE INDSU3,VERSION=10,COMMENT= GLOBAL=.ISU3 ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .ENABL GBL,LC .SBTTL Macro and data definitions .MCALL DEFIN$ DEFIN$ ;Definitions for IND files .PSECT INDSU3 .SBTTL STRSB - String substitution ;+ ;STRSB ;String substitution. ; ; Input: R0 -> input buffer (with possible string symbols) ; ; Output: input buffer copied to "CMDBUF" with strings substituted. ; R0 -> start of output string ; R1 = length of output string ; CMDBL = length of output string ; CMDBE = end of output string (pointer to first unused byte) ; First unused byte in output string = 0 ; SBERR 0: ok ; 1: error ;- .ENABL LSB STRSB:: MOV #CMDBUF,R1 ;Point to start of output buffer CLR SBERR ;Assume success CLR COMFLG ;Set no comment in progress CLR SBFLG ;Set no substitution occurred MOV #,LINLN ;Set maximum line length CMPB (R0),# ;Comment? BNE 10$ ;No DEC COMFLG ;Yes, set line comment 10$: MOVB (R0)+,R2 ;Get next character BEQ 110$ ;Zero is end of line BIT #,.LIFLG ;Is substitution enabled? BEQ 60$ ;No CMPB R2,# ;Yes, comment flag? BNE 30$ ;No TST COMFLG ;Yes, comment in progress? BMI 30$ ;Yes, for whole line? BGT 20$ ;No, end of comment INC COMFLG ;Set start of comment BR 30$ ;Branch around decrement 20$: DEC COMFLG ;Set no comment in progress 30$: CMPB R2,# ;Beginning of string symbol? BNE 60$ ;No CMPB (R0),# ;Is next character apostrophe? BNE 40$ ;No MOVB (R0)+,R2 ;Yes, get it BR 60$ ;Put it in the line ; Do a substitution 40$: INC SBFLG ;Set flag that substitution occured MOVB #,(R1) ;Set temporary end of command buffer SAVE ;Save input buffer address DEC @SP ;Back up saved R0 SAVE ;Save output buffer address CALL GTSY1 ;Get symbol (no leading spaces allowed) BCS 180$ ;Got leading spaces 50$: CALL SRSYM ;Search symbol table for symbol RESTOR BCS 190$ ;Undefined symbol - error CALL CHKPV ; check for %V function, advance R0 if so MOVB SETYP(R5),R2 ;get symbol type BICB #<1>,R2 ;Clear bit to default to octal CMPB R2,# ;Numeric? BEQ 120$ ;Yes CMPB (R0)+,# ;No, is next character single quote? BNE 190$ ;No, error TST (SP)+ ;Skip saved R0 CMPB R2,# ;Logical symbol? BNE 70$ ;No ;+ ;Substitute logical symbol. ;- MOVB #<'T>,R2 ;Assume 'TRUE' BIT #<1>,SETYP(R5) ;Is it true? BEQ 60$ ;Yes MOVB #<'F>,R2 ;Set 'FALSE' 60$: MOV #<1>,R3 ;Set only one character to move BR 100$ ;Move it in ;+ ;String symbol. ;- 70$: MOVB SELEN(R5),R3 ;Get length BEQ 10$ ;Branch back if zero TSTB PVFUNC ; %V found? BEQ 80$ ; branch if not %V function SAVE ; save current input position SAVE ; save output pointer CLR R1 ; get the value of 1st char BISB SEVAL(R5),R1 ; make it 8-bit - no sign extend BR 150$ ; format its numeric value in octal 80$: ADD #SEVAL,R5 ;Point at string value 90$: MOVB (R5)+,R2 ;Get character from string 100$: DEC LINLN ;Room for another character? BMI 200$ ;No, error MOVB R2,(R1)+ ;Yes, store in output buffer DECB R3 ;Any more characters to get in string? BNE 90$ ;Yes, get next one BR 10$ ;No, get next one from input buffer 110$: BR 210$ ; bridge the BR gap with a bucket brigade ;+ ;Substitute numeric symbol. ;- 120$: TSTB PVFUNC ; %V found? BEQ 130$ ; branch if not %V function TST (SP)+ ; discard old saved R0 INC R0 ; point past apostrophe MOVB SEVAL(R5),R2 ; get the numeric value BR 60$ ; insert it as a character. 130$: CLR R4 ;Clear flag CMPB @R0,# ;Trailing dot? BNE 140$ ;No MOVB (R0)+,R4 ;Yes, step past it and set flag 140$: CMPB (R0)+,# ;Next character a single quote? BNE 190$ ;No, error MOV R0,@SP ;Yes, save R0 (overlay old saved R0) SAVE MOV SEVAL(R5),R1 ;Get numeric value 150$: MOV #,R0 ;Get pointer to scratch area CLR R2 ;Suppress leading zeros BIT #<1>,SETYP(R5) ;Decimal? BNE 160$ ;Yes CALL $CBOMG ;No, convert to octal ASCII BR 170$ ;Branch around decimal conversion 160$: CALL $CBDMG ;Convert to decimal ASCII TST R4 ;Trailing dot? BEQ 170$ ;No MOVB R4,(R0)+ ;Yes, insert a dot 170$: RESTOR MOV #,R5 ;Get start of scratch area MOV R0,R3 ;Get end of area SUB R5,R3 ;Get length of numeric string RESTOR BR 90$ ;Go insert string in output buffer 180$: RESTOR 190$: RESTOR ;Restore input buffer address MOVB (R0)+,R2 ;Get character from buffer TST COMFLG ;Comment in progress? BNE 60$ ;Yes, no error 200$: INC SBERR ;Set error 210$: MOV #CMDBUF,R0 ;Get start of output buffer MOV R1,CMDBE ;Save end of output buffer CLRB @R1 ;Clear first unused byte SUB R0,R1 ;Get length MOV R1,CMDBL ;Save it 220$: RETURN .DSABL LSB .SBTTL CHKPV - Check for 'symbol%V' function: ;+ ; CHKPV ; This routine is called by STRSB above, after a defined symbol ; has been found by SRSYM. SRSYM leaves R0 pointing to the character ; just beyond the symbol name. ; ; CHKPV returns with the %V flag (PVFUNC) set only if "%V" is found ; after the symbol name. If "%V is not found, R0 is unchanged, and ; PVFUNC is set to zero. ;- .ENABL LSB CHKPV: CLRB PVFUNC ; reset %V indicator CMPB @R0,#'% ; is next character PERCENT? BNE 20$ ; branch if not MOVB 1(R0),R2 ; get character after % BICB #40,R2 ; convert to upper case CMPB R2,#'V ; is it 'symbl%V' ? BNE 20$ ; branch if not INCB PVFUNC ; indicate %V found CMPB (R0)+,(R0)+ ; point beyond %V 10$: MOVB @R0,R2 ; look at next char BEQ 20$ ; return immediately on NULL CMPB R2,# ; Next character single quote? BEQ 20$ ; if so, return. INC R0 ; eat garbage till APOStrophy seen BR 10$ 20$: RETURN .DSABL LSB .SBTTL TBSRC - search string table ;+ ;TBSRC ;Search string table for match with input buffer. ; ; Input: R0 - buffer address ; R2 - Start of table, table entries end with zero byte and table ; ends with zero byte ; ; Output: R1 - Index into TABLE*2 ; Carry clear match found ; R0 - updated ; Carry set no match found ; R0 - unchanged ;- .ENABL LSB TBSRC:: CLR R1 ;Zero table index 1$: MOV R0,R3 ;Copy buffer pointer CALL CMPAR ;Is this a match? BCC 3$ ;Yes 2$: TSTB (R2)+ ;No, skip to next command BNE 2$ ;Loop til next TST (R1)+ ;Update index by two TSTB (R2) ;End of table? BNE 1$ ;No, try next entry SEC ;Yes, error BR 4$ ;Don't update buffer pointer 3$: MOV R3,R0 ;Update R0 4$: RETURN .DSABL LSB .SBTTL GSVAL - Get string value ;+ ;GSVAL ;Get string value from input string. Either locates a string constant ;enclosed in double quotes, or finds a string symbol. ; ; Input: R0 -> input string ; ; Output: R0 -> input string (updated) ; R1 = length of string ; R5 = pointer to string ; ; If error: ; Calls error processing directly (no return to caller). ; ; Registers altered: R0,R1,R2,R5 ;- .ENABL LSB GSVAL:: SAVE MOV #SCR1,-(SP) ;Set start address of scratch area 1$: CALL $GNBLK ;Get next character BCS 13$ ;Syntax error CMPB R2,# ;Is first character quote? BNE 4$ ;No MOV #STRLEN,R4 ;Set maximum length of string SAVE ;Save start of string 2$: MOV R0,R1 ;Copy character pointer MOVB (R0)+,R2 ;Get character BEQ 3$ ;End of line - get out of loop CMPB R2,# ;End of string? BEQ 3$ ;Yes DEC R4 ;Room for more? BMI 16$ ;String length too large BR 2$ ;Get next character 3$: RESTOR ;Get pointer to start of string SUB R5,R1 ;Get length BR 10$ ;+ ;First character in the string was not a quote. ;- 4$: DEC R0 ;Backup to first character CALL GTSY1 ;Get symbol (no spaces allowed) BCS 13$ ;Syntax error CALL SRSYM ;Find symbol entry BCS 14$ ;Symbol not found CMPB SETYP(R5),# ;String symbol? BNE 15$ ;No, wrong symbol type CLR -(SP) ;Assume no index, set low index = 0 CMPB @R0,# ;Indices given? BNE 7$ ;No CLR LIM1 ;Initialize radix bytes for high & low limits TSTB (R0)+ ;Step past [ MOV R0,LOW ;Store the address of start of low limit CALL EVNX ;Get low index MOVB SYMTP,LIM1 ;Store the radix returned DEC R1 ;Adjust to range 0,1,... BMI 17$ ;Bad range or default specification MOV R1,@SP ;Save it CMPB (R0)+,# ;Next character must be : BNE 13$ ;Syntax error MOV R0,HIGH ;Store the address of start of high limit CALL EVNX ;Get high index CMPB (R0)+,# ;Next character must be ] BNE 13$ ;Syntax error MOVB SYMTP,LIM2 ;Store high limit radix ;+ ;The low bit of the bytes LIM1 and LIM2 determine if the value returned was ;decimal or octal. If decimal, the bit is set. If the low bit of each word ;are set or cleared (equal to each other) no further changes need to be made. ;If they are not equal the one not set must be changed to decimal and the ;value must be re-calculated to decimal. ;- BIC #<177376>,LIM1 ;Clear all but low bit of each byte CMPB LIM1,LIM2 ;Are they equal? BEQ 6$ ;Yes, no further changes TSTB LIM2 ;Is the high limit decimal? BNE 5$ ;Yes, change low limit to decimal MOVB #,@R1 ;End range specification MOVB #,-(R0) ;Place . to force decimal MOV HIGH,R0 ;Get address of high limit for decimal calc CALL EVNX ;Get high index BR 6$ ;No need to go further 5$: MOV HIGH,R0 ;Point to start of high limit MOVB #,@R0 MOVB #,-(R0) ;Place . to force decimal MOV LOW,R0 ;Point to start of low limit SAVE CALL EVNX ;Get high index DEC R1 ;Adjust to range 0,1,... MOV R1,-2(SP) ;Store it on stack RESTOR 6$: CMP R1,#<132.> BHIS 17$ CMPB R1,SELEN(R5) ;Too high? BLE 8$ ;No 7$: CLR R1 BISB SELEN(R5),R1 ;Get last character index + 1 8$: SUB @SP,R1 ;Subtract index of first to get length BHIS 9$ ;Branch if ok CLR R1 ;Set length = 0 9$: ADD #SEVAL,R5 ;Point at start of string value ADD (SP)+,R5 ;Add low index 10$: MOV @SP,R4 ;Get current pointer in scratch buffer 11$: DEC R1 ;Any more to copy? BMI 12$ ;No CMP R4,#SCR1E ;End of scratch buffer? BHIS 16$ ;Yes, string length too large MOVB (R5)+,(R4)+ ;Copy character BR 11$ ;Loop 12$: MOV R4,@SP ;Update pointer in scratch buffer CMPB (R0)+,# ;Next = plus sign? BEQ 1$ ;Yes - do more MOV #SCR1,R5 ;Get start of scratch buffer RESTOR ;Get current pointer in scratch buffer SUB R5,R1 ;Get length RESTOR RETURN 13$: TRAP ERSYN ;Syntax error 14$: TRAP ERUDS ;Undefined symbol 15$: TRAP ERTYP ;Wrong symbol type 16$: TRAP ERRSZ ;String expression exceeds limit 17$: TRAP ERBRD ;Bad range or default specification .DSABL LSB .SBTTL ASVALN - Assign numeric value ;+ ;ASVALN ;Assign value to numeric symbol. ; ; Input: R0 -> to ASCII string representing numeric value ; R5 -> to symbol table entry ; ; Output: value is stored in symbol table entry ; ; If error: syntax error trap (no return to caller) ; ; Registers altered: R0,R1,R2 ;- ASVALN::CALL EVNX ;Evaluate numeric expression BCS 1$ ;Branch with carry set if error MOV R1,SEVAL(R5) ;Store it MOVB #2,SETYP(R5) ;Assume octal mode BIT #,.LIFLG ;Octal mode? BNE 1$ ;Branch if yes MOVB #3,SETYP(R5) ;Set decimal 1$: RETURN .SBTTL EVNX - evaluate numeric expression ;+ ;EVNX ;Evaluate a numeric expression. ; ; Input: R0 -> command buffer ; ; Output: R0 -> just beyond end of numeric expression (delimiter is space or ; null) ; R1 = numeric value ; SYMTP = "OCT" if all symbols and constants were octal ; "DEC" if at least one was decimal. ; ;Registers altered: R0,R1,R2 .ENABL LSB ;+ ;Operator scan table. ;Since FALSE is internally a 1 and TRUE is 0 negative logic must be ;used on all .SETL processing. The only operators involved are !, &, and ^. ;The positions are checked before processing the operator to ensure we ;don't get confused with mixed mode. ;- SCANT: .ASCIZ /+/ ;Add .ASCIZ /-/ ;Subtract or uniary minus .ASCIZ /*/ ;Multiply .ASCIZ !/! ;Divide NEGLOG: ;Next operators can be involved with negative ;logic for SETL .ASCIZ /(/ ;Coerce evaluation .ASCIZ /)/ ;Reap coercion .ASCIZ /!/ ;Logical OR .ASCIZ /&/ ;Logical AND .ASCIZ /^/ ;Logical NOT .ASCIZ /.OR/ ;Logical OR .ASCIZ /.AND/ ;Logical AND .ASCIZ /.NOT/ ;Logical NOT .BYTE 0 ;End of table seenp: .byte 0 ;paren seen flag stchr: .byte 0 ;string-char function mode flag PVFUNC: .BYTE 0 ; "%V is specified" flag .EVEN ;+ ;Entry symbols for above operaters. ; OPTAB: .WORD 2$,4$,10$,12$,22$,26$,18$,20$,28$,118$,120$,218$ 2$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)+R1 ;- PLUS: ADD R1,@SP BR 8$ 4$: TSTB FLAG1 ;Expecting an expression? BNE 6$ ;Branch if operator is expected MOV #NEGOP,-(SP) ;Set up return for uniary minus routine BR NEXT ;Go get the operand 6$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)-R1 ;- SUB R1,@SP 8$: BCS OVFER ;Branch if overflow error BR NEXT ;Go get the operand NEGOP: NEG R1 ;Do uniary minus routine, negate accumulator JMP @(SP)+ ;Go do operation 10$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)*R1 ;- SAVE MOV 2(SP),R0 CALL $MUL TST R0 BNE OVFER ;Branch if overflow MOV R1,R0 BR 14$ 12$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)/R1 (remainder is lost) ;- TST R1 ;Check for zero divisor BEQ OVFER ;Branch if overflow SAVE MOV 2(SP),R0 CALL $DIV 14$: MOV R0,2(SP) RESTOR BR NEXT ;Go get the operand 16$: COMB FLAG1 ;Next = expression BNE 24$ ;Expression was already expected - error BR NEXT ;Go get the operand 118$: TSTB SETLFL ;In the process of SETL? BEQ 219$ ;No get out 18$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)!R1 (log. inclusive OR) ;- TSTB SETLFL ;Processing SETL (negative logic)? BNE 21$ ;Yes, then really do a logical AND 19$: BIS R1,@SP BR NEXT ;Go get the operand 120$: TSTB SETLFL ;In the process of SETL? BEQ 219$ ;No get out 20$: CALL 16$ ;Check current context ;+ ; 0(SP) <-- 0(SP)&R1 (LOG. AND) ;- TSTB SETLFL ;Processing SETL (negative logic)? BNE 19$ ;Yes, then really do a logical OR 21$: COM R1 BIC R1,@SP BR NEXT ;Go get the operand ;+ ;Left parenthesis detected ;- 22$: incb seenp ;mark as seen TSTB FLAG1 ;Expression expected? 24$: BEQ 25$ SYNER1: JMP SYNER ;No, error 25$: INCB PARCNT ;Increment parentheses nesting level BR EVNX0 ;+ ;Right parenthesis detected ;- 26$: DECB PARCNT ;Decrement parentheses nesting level BMI SYNER1 ;Went negative - error BR END1 ;+ ;Logical NOT ;- 218$: TSTB SETLFL ;In the process of SETL? 219$: BEQ END ;No get out 28$: COMB FLAG1 ;This is a uniary operator BEQ SYNER1 ;and a syntax error if used as binary CALL 16$ ;Check context and push operation address COM R1 ;Complement accumulator JMP @(SP)+ ;Go to next function OVFER: TRAP ERNOV ;Numeric overflow EVNX:: CLR FLAG1 ;Clear flag and PARCNT clrb seenp ;Not yet seen parenthesis MOVB #NUMOCT,SYMTP ;Assume result is OCTAL CALL $GNBLK ;Get first non-blank DEC R0 ;Back up pointer BCS SYNER ;End of line - error SAVE CALL EVNX0 RESTOR CLRB SETLFL ;Reinit SETL special flag (negative logic) clrb stchr ;Reset mode from string-character RETURN EVNX0: CLR -(SP) ;Initialize result to zero MOV #,-(SP) ;Set first operation = ADD NEXT: MOV R0,R5 ;Save pointer tstb stchr ;Are we in string-char function mode? beq 288$ ;If not, branch out. tstb parcnt ;inside parens now? bne 288$ ;continue if so. tstb seenp ;already seen parentheses? bne end ;if so, get out now. 288$: CALL $GNBLK ;Get next non-blank character DEC R0 ;Back up pointer BCS END ;Branch out if end of line ;Take out next two instructions to allow spaces and tabs in expressions. ; TST R1 ;Any blanks? ; BNE END ;Yes, exit MOV #SCANT,R2 ;Pnt to scan tbl for operators & parentheses CALL TBSRC ;Search for match BCS 30$ ;No match - must be symbol or constant TSTB SETLFL ;Processing SETL? BEQ 29$ ;Branch if no CMP R1,# ;Is operator logical? BLO MIXOP ;Branch if no - error 29$: JMP @OPTAB(R1) ;Found - go to routine to handle it 30$: CMPB @R0,#'0 ;Numeric value? BLO 32$ ;No, may be dollar sign CMPB @R0,#'9 ;Test high end for numeric value BLOS 40$ ;Yes, numeric 32$: CALL GTSY1 ;Get symbol (no blanks allowed) BCS END ;Error - exit COMB FLAG1 ;Get operator BEQ END2 ;No operator - new command CALL SRSYM ;Search symbol table for it BCS UDFER ;Undefined symbol - error CLR R1 ;Initialize MOVB SETYP(R5),R1 ;Get symbol type BIT #,R1 ;String symbol? BNE TYPER ;Yes, symbol type error BIT #,R1 ;Numeric BEQ DOAR ;Branch if logical ;+ ;Numeric ;- ASR R1 ;Move low bit to carry BCS 36$ ;Skip type if decimal type BIT #,.LIFLG ;Octal or decimal mode BNE 38$ ;Octal 36$: BISB #1,SYMTP ;Set to decimal 38$: MOV SEVAL(R5),R1 ;Get value BR DOAR ;Go do arithmetic operation 40$: COMB FLAG1 ;Next is operator BEQ SYNER ;No operator - error CALL $GTNUM ;Get numeric constant BCS OVFER ;Numeric under or overflow DEC R0 ;Back up pointer CMPB -1(R0),# ;Ends with a dot? BEQ 42$ ;Branch if yes BIT #,.LIFLG ;Octal or decimal mode BNE DOAR ;Octal 42$: BISB #1,SYMTP ;Yes, update the symbol type DOAR: JMP @(SP)+ ;Go to arith. rtn. - address on top of stack END2: COMB FLAG1 ;Reset so don't syntax error END: MOV R5,R0 ;Restore R0 to point where scan failed TSTB PARCNT ;Parentheses nesting level = 0? BNE SYNER ;No, error END1: TSTB FLAG1 ;Expecting an expression? BEQ SYNER ;Yes, error RESTOR ;Get result so far RETURN ;Return to next higher level or get out MIXOP: CLRB SETLFL ;Make sure the .SETL flag is off TRAP ERMIX ;Mixed operators on logical operation SYNER: CLRB SETLFL ;Make sure the .SETL flag is off TRAP ERSYN ;Syntax error UDFER: CLRB SETLFL ;Make sure the .SETL flag is off TRAP ERUDS ;Undefined symbol TYPER: TRAP ERTYP ;Symbol not numeric .DSABL LSB .END