.TITLE SCP - SUBSTITUTION COMMAND PARSER .IDENT /MB.01/ ;+ ; SUBSTITUTION COMMAND PARSER TO BE USED AS A PART OF ...CA. SECCONDARY ; COMMANDS INTERPRETER (CATCH ALL TASK) FOR RSX11M V3.2 AND LATER. ; THE TABLE DRIVEN SCP RECOGNIZES COMMANDS UPON FIRST THREE LETTERS ; WITH THE EXCEPTION OF "NO" PREFIXED COMMANDS (HOLD/NOHOLD ETC.), ; WHERE FIVE LETTERS ARE REQUIRED. ; EVERY RECOGNIZED COMMAND IS PARSED TO INDIVIDUEL PARAMETERS, ; USING COMMAND SPECIFIC (OR DEFAULT) SEPARATORS. ; SPECIAL PARAMETERS (QUALIFIER STRING, WHOLE COMMAND STRING) ARE ; PARSED SEPARATELY. ; THE NEW (SUBSTITUTED) COMMAND IS FORMED FROM THE PROTOTYPE ONE, ; USING CONDITIONAL EXPANSION AND PARAMETER SUBSTITUTION. ; COMMAND, AS RESULT OF AN SUBSTITUTION STEP, MAY BE EITHER INPUT ; FOR NEXT SUBSTITUTION STEP, OR INTERNAL SCP COMMAND (TCF), ; OR WILL BE PASSED TO MCR... AS THE NEW COMMAND. ; ; TCF (TERMINAL CONTROL FUNCTINS) ; THIS COMMAND SIMPLIFIES CODING OF TERMINAL-CONTROL COMMANDS, ; RESULT OF TCF COMMAND IS CHARACTER STRING WRITEN TO TI: TERMINAL. ; EXAMPLE OF SYNTAX: ; ; >TCF 15,12,"MESSAGE",7,7 ; ; PARAMETER STRING CONSISTS OF OCTAL BYTE VALUES TO BE WRITTEN ; TO ISSUING TERMINAL, OR (TO SIMPLIFY CODING) ASCII STRING ; CLOSED WITHIN DOBLE-QUOTES. ; ; ; BASIC MODULE FLOW IN SHORT: ; ; SCPAR:: - FIND END OF INPUT COMMAND STRINGE (ESCAPE OR CR) ; ; SEARCH: - SERCH TABLE IF COMMAND MAY BE SUBSTITUTED; ; IF NOT RECOGNIZED, EITHER RETURN TO CALLER(CA), OR ; (IF IT WAS YET SUBSTITUTED) CHAIN MCR... WITH IT. ; ; 100$: - SEPARATE CURRENT COMMAND STRING TO INDIVIDUEL PARAMS. ; FIRST FIND SPECIAL PARAMETERS: ; ?/? - QUALIFIERS CLOSELY CONNECTED TO COMMAND ; ?0? - WHOLE PARAMETER STRING (SEPARATED BY SPACE) ; THEN DIVIDE ?0? TO PARAMETERS ?1?,?2? ... ; ; SUBST:: - TAKE PROTOTYPE COMMAND STRING AND EXPAND IT INTO ; OUTPUT BUFFER USING CONDITIONAL PARAMETER SUBSTITUTION. ; SET INPUT COMMAND POINTER TO RESULTING STRING AND ; TRY NEXT SUBSTITUTION STARTING AT SEARCH:: ; ; NOTE: IF PARTICULARLY CONFIGURED AT ASSEMBLY TIME, COMMA WILL ; (WILL NOT) BE RECOGNIZED AS SEPARATOR WITHIN UIC-SPEC. ; ; SIMILARLY, COMMANDS WITH REQUIRED PARAMETER MISSING WILL ; (WILL NOT) BE PASSED BACK TO CALLER (TO PASS THEM TO CCL) ; INSTEAD OF FINISH "DCL -- REQUIRED FILESPEC MISSNG". ; (LIMITED TO FIRST, THIRD ETC. STEP OF SUBSTITUTION) ; ; ; DETAILED DESCRIPTION OF SCP COMMANDS IS INCLUDED IN CATAB.MAC, ; WHICH SHOULD DEFINE ALL REQUIRED TABLES USING SPECIAL MACROS. ;- ; ; LOCAL DEFINITONS ; ;DEBUG= 1 ;INCLUDE COMMANDS DEBUGING CODE PASCCL= 1 ;PASS COMMAND TO ...CCL IF REQUIRED PARAM. MISSING UICREC= 1 ;ALLOW UIC RECOGNITION (DON'T RECOGNIZE "," WITHIN UIC) PARNUM= 11. ;NUMBER OF PARAMETERS ALLOWED ESC= 33 ;SYMBOL FOR ESCAPE SPA= 40 ;SYMBOL FOR SPACE CR= 15 ;SYMBOL FOR CARRIAGE-RETURN LUN= 1 ;LUN FOR TI: I/O .PAGE ; ; LOCAL MACROS ; .MCALL EXST$S,QIOW$S,QIOW$,DIR$ ; .MACRO ERRM,N,TXT ;GENERATE TEXT FO RERROR MESSAGE EMM'N: .ASCII /TXT/ EML'N= .-EMM'N .ENDM ; .MACRO ERROR,N,A ;SET-UP QIO DPB FOR ERROR MESSAGE MOV #EMM'N,QIOW+Q.IOPL MOV #EML'N,QIOW+Q.IOPL+2 JMP A .ENDM ; .IF DF DEBUG .MACRO CHECK,A,B ;TYPE-OUT BUFFER POINTED BY A, LENGTH B MOV A,QIOW+Q.IOPL MOV B,QIOW+Q.IOPL+2 DIR$ #QIOW .ENDM .ENDC ;DEBUG ; ; LOCAL DATA ; QIOW: QIOW$ IO.WVB,LUN,31,,,,<0,0,40> ;TI: I/O DPB CMDNAM: .WORD 0 ;COMMAND NAME RADIX-50 SAVE INPCMD: .WORD 0 ;INPUT COMMAND FIRST CHAR ADDR INPCME: .WORD 0 ;INPUT COMMAND LAST CHAR ADDR OUTCMD: .WORD 0 ;OUTPUT COMMAND FIRST CHAR ADDR OUTCME: .WORD 0 ;OUTPUT COMMAND LAST CHAR ADDR PROTOT: .WORD 0 ;PROTOTYPE COMMAND ADDR SAVE CONDIT: .WORD 0 ;CONDITIONAL COPY LEVEL COUNTER PARPNT: .BLKW PARNUM ;PARAMETER STRINGS ADDR SAVE PARLEN: .BLKW PARNUM ;PARAMETER STRINGS LENGTH SAVE WRK: .BLKW 40. ;WORK BUFFER FOR SUBSTITUTED COMMAND TCFNAM: .RAD50 /TCF/ ;TCF COMMAND NAME RADIX 50 NOPRE: .BYTE 0 ;FLAG FOR "NO" COMMAND PREFIX ENDCH: .BYTE 0 ;SAVE FOR FINISHING CHAR OF CMD .NLIST BEX BASSEP: .ASCIZ ;BASIC SEPARATORS - LINE FINISHERS SPASEP: .ASCIZ / / ;SPACE SEPARATOR KEYSEP: .ASCIZ %/% ;QUALIFIER SEPARATOR PARSEP: .ASCIZ / =,/ ;PARAMETER SEPARATORS ; ERRM 1, ERRM 2, ERRM 3, ERRM 4, ERRM 5, ERRM 6, ERRM 7, .EVEN .PAGE ; MAIN ROUTINE ENTRY ; ; FIRST FIND FINISHING CHARACTER AND REPLACE IT BY ZERO ; SCPAR:: MOV #MCR,R4 ;POINT TO COMMAND LINE START MOV #BASSEP,R3 ;POINT TO BASIC SEPARATORS CALL FNDSEP ;FIND FIRST OF THEM MOVB -(R4),ENDCH ;SAVE IT CLRB (R4) ;AND REPLACE BY ZERO CLRB 1(R4) ;ALSO NEXT BYTE CLEAR FOR FNDSEP MOV R4,INPCME ;SAVE END OF COMMAND POSITION MOV #MCR,INPCMD ;AND ALSO START OF COMMAND MOV #WRK,OUTCMD ;PREPARE OUTPUT COMMAND ADDR CLR CMDNAM ;MARK NO VALID COMMAND ; ; SEARCH IF CURRENT COMMAND MAY BE PROCESSED BY SUBSTITUTION ; SEARCH::MOV INPCMD,R0 ;POINT TO COMMAND TO PROCESS CLRB NOPRE ; CMPB #'N,(R0) ;CHECK IF PREFIX "NO" PRESENT BNE 10$ ;NE = NO CMPB #'O,1(R0) ; BNE 10$ ;NE = NO INCB NOPRE ;MARK "NO" PREFIX PRESENT ADD #2,R0 ;POINT AFTER "NO" 10$: MOV #1,R1 ;ALLOW DOTS CONVERSION CALL $CAT5B ;CONVERT COMMAND TO RADIX 50 CMP R1,TCFNAM ;TCF COMMAND ? BEQ 35$ ;EQ = YES 20$: MOV #CMDTAB,R3 ;POINT TO START OF VALID COMMAND TABLE TSTB NOPRE ;"NO" PREFIXED COMMAND ? BEQ 30$ ;EQ = NO MOV #NOPTAB,R3 ;POINT TO START OF "NO" PREFIXED CMD 30$: MOV (R3)+,R0 ;GET CURRENT COMMAND FROM TABLE BEQ 40$ ;EQ = END OF TABLE TST (R3)+ ;SKIP OVER PROTOTYPE STRING ADDR CMP R1,R0 ;COMPARE OUR COMMAND TO TABLE BNE 30$ ;NE = NOT MATCH, TRY NEXT MOV -(R3),PROTOT ;SAVE PROTOTYPE COMMAND STRING ADDR 35$: MOV R1,CMDNAM ;SAVE MATCHED COMMMAND NAME BR 100$ ;GO AND PROCEED IT ; 40$: MOVB ENDCH,@INPCME ;RESET FINISHING CHAR. TST CMDNAM ;CHECK, IF ANY VALID COMMAND WAS FOUND BNE 50$ ;NE = YES, GIVE IT TO MCR... RETURN ;OTHERWISE RETURN TO CALLER TO PROCEED 50$: MOV INPCMD,R5 ;POINT TO CURRENT COMMAND JMP CHMCR ;AND CHAIN MCR... WITH IT ; ; SUBSTITUTED COMMANDS MUST (IN GENERAL) HAVE FOLLOWING FORM: ; ; ; 100$: MOV #PARPNT,R0 ;POINT TO POINTERS VECTOR MOV #PARLEN,R1 ;POINT TO LENGTH VECTOR MOV #PARNUM,R2 ;GET COUNT 110$: CLR (R0)+ ;CLEAR ALL PARAMETER CLR (R1)+ ;DESCRIPTORS SOB R2,110$ ;LOOP ; ; PREPARE DEFAULT PARAMETER "?0?" - COMPLETE PARAMETER LIST ; 120$: MOV #2,R5 ;GET PARAMETER ?0 INDEX MOV INPCMD,R4 ;POINT TO COMMAND START MOV #SPASEP,R3 ;POINT TO SPACE AS SEPARATOR CALL FNDSEP ;TRY TO FIND A SPACE BCS 130$ ;CS - NO SPACE = NO PARAMETER LIST MOV R4,PARPNT(R5) ;SAVE POINTER TO START OF PARAMETER LIST MOV INPCME,PARLEN(R5) ;GET FINISHING. CHAR POSITION SUB R4,PARLEN(R5) ;COMPUTE PARAMETER LIST LENGTH 130$: CMP TCFNAM,CMDNAM ;TCF COMMAND ? BNE 140$ ;NE = NO MOV PARPNT(R5),R5 ;POINT TO START OF PARAMETER LIST JMP TCF ;CHAIN TCF ROUTINE ; ; PREPARE DEFAULT PARAMETER "?/?" - COMMAND QUALIFIERS ; 140$: MOV INPCMD,R4 ;POINT TO START OF COMMAND MOV #KEYSEP,R3 ;POINT TO QUALIFIERS SEPARATOR CALL FNDSEP ;TRY TO FIND IT BCS 150$ ;CS = NO QUALIFIERS MOV PARPNT(R5),PARLEN ;GET PARAMETER LIST START POSITION BNE 145$ ;NE = IT EXISTS MOV INPCME,PARLEN ;GET FINISHING CHAR. POSITION INC PARLEN ;AND POINT AFTER IT 145$: SUB R4,PARLEN ;COMPUTE QUALIFIERS LENGTH BGT 148$ ;GT = QUALIFIERS EXIST CLR PARLEN ;MARK NO QUALIFIERS BR 150$ ; 148$: DEC R4 ;POINT TO FIRST "/" OF QUALIFIERS MOV R4,PARPNT ;AND SAVE IT ; ; PARSE PARAMETER LIST TO INDIVIDUEL PARAMETERS "?N?" ; 150$: MOV PROTOT,R3 ;GET SEPARATORS STRING FROM PROTOTYPE TSTB (R3) ;NON - STANDARD SEPARATORS PRESENT ? BNE 151$ ;NE = YES MOV #PARSEP,R3 ;NO = USE STANDARD SEPARATORS 151$: MOV PARPNT(R5),R4 ;POINT TO START OF PARAMETER LIST BEQ SUBST ;EQ = NO SUCH LIST 152$: TST (R5)+ ;POINT TO NEXT PARAMETER DESCRIPTORS CMP #2*PARNUM,R5 ;CHECK IF LIST NOT EXPIRED ? BGE 154$ ;GE = NOT YET JMP ERR2 ;REPORT TOO MANY PARAMETERS AND EXIT 154$: MOV R4,PARPNT(R5) ;SAVE START OF CURR. PARAMETER CALL FNDSEP ;TRY TO FIND IT'S END MOV R4,PARLEN(R5) ;GET POINTER TO NEXT PARAMETER SUB PARPNT(R5),PARLEN(R5) ;AND COMPUTE PARAMETER LENGTH DEC PARLEN(R5) ; .IF DF DEBUG CHECK PARPNT(R5),PARLEN(R5) ;DISPLAY EXTRACTED PARAMETER .ENDC ;DEBUG CMP R4,INPCME ;END OF COMMAND REACHED ? BLO 152$ ;LO = NOT YET, LOOP FOR NEXT PAR. .PAGE ; ; SUBSTITUTE PARAMETERS INTO PROTOTYPE COMMAND ; SUBST:: MOV OUTCMD,R3 ;POINT TO OUTPUT COMMAND START MOV PROTOT,R4 ;POINT TO PROTOTYPE COMMAND START 5$: TSTB (R4)+ ;START OF PROTOTYPE FOUND ? BNE 5$ ;NE = NOT YET, IN SEPARATOR TABLE MOV R3,R5 ADD #79.,R5 ;SET UP SENTINEL FOR CMD LENGTH ; 10$: MOVB (R4)+,R0 ;GET NEXT PROTOYPE BYTE BEQ 70$ ;EQ = END OF PROTOTYPE CMPB #'$,R0 ;FORCED END OF SUBSTITUTION ? BEQ 70$ ;EQ = YES CMPB #'?,R0 ;SUBSTUTUTION SYMBOL "?" ? BEQ 20$ ;EQ = YES CMPB #'),R0 ;END OF CONDITIONAL COPY ? BEQ 10$ ;EQ = YES, IGNORE CMPB #'(,R0 ;BEGIN OF CONDITIONAL COPY ? BEQ 15$ ;EQ = YES MOVB R0,(R3)+ ;COPY CURRENT BYTE TO OUTPUT CMP R3,R5 ;CMD TOO LONG ? BLO 10$ ;LO = NOT YET BR 601$ ;ERROR 1 - TOO LONG 15$: CALL 80$ ;CHECK PAR.INDEX VALIDITY TST PARLEN(R0) ;PARAMETER EXISTS ? BNE 10$ ;NE = YES,CONTINUE COPY MOV #1,CONDIT ;SET UP FIRST LEVEL OF () 17$: MOVB (R4)+,R0 ;GET NEXT CHARACTER BEQ 70$ ;ZERO = END OF PROTOTYPE CMPB #'(,R0 ;HIGHER LEVEL CONDITIONAL ? BNE 18$ ;NE = NO INC CONDIT ;INCREASE PARENTHESIS LEVEL 18$: CMPB #'),R0 ;END OF CONDITIONAL MARK ? BNE 17$ ;NE = NO, SKIP IT DEC CONDIT ;DECREMENT PARENTHESIS LEVEL BEQ 10$ ;EQ = END OF CUR. CONDITIONAL BR 17$ ;NE = KEEP ON SKIPPING 20$: CALL 80$ ;CHECK PAR.INDEX VALIDITY MOV PARPNT(R0),R2 ;POINT TO PARAMETER STRING BEQ 50$ ;EQ = NO SUCH PARAMETER MOV PARLEN(R0),R1 ;GET PARAMETER LENGTH BEQ 50$ ;EQ = NO SUCH PARAMETER 30$: MOVB (R2)+,(R3)+ ;COPY PARAMETER CMP R3,R5 ;CMD TOO LONG ? BHI 601$ ;HI = YES, ERROR 1 SOB R1,30$ ;LOOP IF MORE CHAR. CMPB #'#,(R4) ;CURRENT PARAMETER REQUIRED ? BEQ 45$ ;EQ = YES, O.K. 40$: CMPB #'?,(R4) ;CURRENT PARAMETER MANDATORY ? BNE 604$ ;NE = SYNTAX ERROR 45$: INC R4 ;POINT TO NEXT CHAR. BR 10$ ;AND CONTINUE 50$: CMPB #'#,(R4) ;CURRENT PARAMETER REQUIRED ? BNE 40$ ;NE = NOT, ONLY CHECK SYNTAX ; .PAGE .IF DF PASCCL 606$: CMP #MCR,INPCMD ;WORKING ON MCR BUFFER ? BNE 666$ ;NE - REPORT REQUIRED PARAMETER MISSING MOVB ENDCH,@INPCME ;APPEND FINISHING CHARACTER RETURN ;RETURN TO CALLER TO PASS CMD TO CCL 666$: JMP ERR6 ;REQUIRED PARAMETER MISSING .IFF ;PASCCL 606$: JMP ERR6 ;REQUIRED PARAMETER MISSING .ENDC ;PASCCL 601$: JMP ERR1 ;COMMAND TOO LONG 603$: JMP ERR3 ;PARAMETER INDEX INVALID 604$: JMP ERR4 ;SUBSTITUTION COMMAND SYNTAX ERROR ; 70$: CLRB (R3) ;APPEND ZERO BYTE CLRB 1(R3) ;AND ONE MORE MOV R3,-(SP) ;SAVE POINTER TO LAST BYTE MOV OUTCMD,-(SP) ;SAVE POINTER TO FIRST BYTE MOV INPCMD,OUTCMD ;CHANGE DESCRIPTORS - JUST SUBSTITUTED MOV INPCME,OUTCME ;COMMAND (OUTPUT) WILL BE NOW USED MOV (SP)+,INPCMD ;AS INPUT FOR NEXT SUBSTITUTION MOV (SP)+,INPCME ; .IF DF DEBUG SUB INPCMD,R3 ;COMPUTE STRING LENGTH CHECK INPCMD,R3 ;DISPLAY INPUT FOR NEXT PROCESSING .ENDC ;DEBUG JMP SEARCH ; ; CHECK VALIDITY OF PARAMETER INDEX ; 80$: MOVB (R4)+,R0 ;GET PARAMETER INDEX SYMBOL SUB #'/,R0 ;CONVERT IT TO NUMERIC INDEX BLT 603$ ;LT = INVALID, SYNTAX ERROR CMP #PARNUM,R0 ;LEGAL PARAMETER INDEX ? BLT 603$ ;LT = INVALID, SYNTAX ERROR ASL R0 ;COMPUTE WORD INDEX RETURN .PAGE ;+ ; FNDSEP - FIND ANY OF PRESCRIBED SEPARATORS IN A STRING ; ; INPUT: R4 - POINTER TO STRING FINISHED WITH ZERO ; R3 - POINTER TO LIST OF SEPARATORS FINISHED WITH ZERO ; ; OUTPUT: R4 - POINTS TO NEXT BYTE AFTER FOUND SEPARATOR ; CS - END OF STRING REACHED, R4 POINTS AFTER ZERO BYTE ; ; CONDITIONAL UICREC ALLOW TO GENERATE VERSION, WHICH WILL NOT ; RECOGNIZE COMMA WITHIN UIC SPECIFICATION AS A VALID SEPARATOR ; EVEN IF COMMA WILL BE IN SEPARATORS TABLE: ; ; EXAMPLE: PARSING STRING [12,344]ALFA.DMP,BETA,GAMA ; .IF DF UICREC SEARCH FOR "," STOPS AFTER [12,344]ALFA.DMP ; .IFNDF UICREC SEARCH FOR "," STOPS AFTER [12 ;- UNRSEP::.WORD 0 ;UNRECOGNIZED SEPARATOR ; FNDSEP::MOVB (R4)+,R0 ;GET NEXT BYTE BEQ 20$ ;EQ = END OF STRING REACHED .IF DF UICREC ;IF UIC RECOGNITION REQUIRED CMPB #'[,R0 ;IS THIS UIC-START ? BNE 5$ ;NE = NO MOVB #',,UNRSEP ;SET-UP UNRECOGNIZED SEP = COMMA 5$: CMPB #'],R0 ;IS THIS UIC-END ? BNE 8$ ;NE = NO CLR UNRSEP ;CLEAR UNRECOGNIZED SEPARATOR .ENDC ;UICREC 8$: MOV R3,R2 ;COPY SEPARATORS POINTER 10$: MOVB (R2)+,R1 ;GET SEPARATOR BEQ FNDSEP ;EQ = END OF SEPARATOR TABLE CMPB UNRSEP,R1 ;THIS SEPAR SHOULD NOT BE RECOGNIZED ? BEQ 10$ ;EQ = YES, SO GET NEXT SEP. CMPB R0,R1 ;COMPARE CHAR & SEPARATOR BNE 10$ ;NE = TRY NEXT SEPAR. CLC ;MARK SEPARATOR FOUND RETURN 20$: SEC ;MARK SEPARATOR NOT FOUND RETURN ; ; ERROR REPORT COMMANDS ; ERR1: ERROR 1,ERRSEV ;REPORT ERROR ERR2: ERROR 2,ERRSEV ERR3: ERROR 3,ERRSEV ERR4: ERROR 4,ERRSEV ERR5: ERROR 5,ERRSEV ERR6: ERROR 6,ERRSEV ERR7: ERROR 7,ERRSEV ; ERRSEV: DIR$ #QIOW ;OUTPUT ERROR TEXT EXST$S #EX$SEV ;AND SET-UP BAD NEWS .PAGE ; ; TCF - Terminal control functions ; TCF: TST R5 ; Any parameter list ? BEQ 55$ ; EQ = no, simply exit MOV OUTCMD,R0 ; Set output buffer addr 10$: CLR R1 ; Prepare output byte 15$: MOVB (R5)+,R2 ; Pick up new byte BEQ 50$ ; EQ = end of command CMPB #'",R2 ; Double quote ? BNE 18$ ; Ne = no TST R1 ; Any value in progress ? BNE 19$ ; Ne = yes, so error 16$: MOVB (R5)+,R2 ; Get next char BEQ 50$ ; EQ = end of string, finished CMPB #'",R2 ; Double quote (finishing) ? BEQ 15$ ; EQ = yes, string finished MOVB R2,(R0)+ ; Copy char. directly BR 16$ ; And try to get next 18$: CMPB #',,R2 ; Comma? BEQ 40$ ; EQ = yes, finish current char. CMPB #' ,R2 ; Space? BEQ 35$ ; EQ = yes, finish current char. CMPB #'0,R2 ; Char. value GE symbol zero? BLE 20$ ; LE = yes, O.K. 19$: JMP ERR5 ; Report syntax error 20$: CMPB #'7,R2 ; Char. value LE symbol seven? BGE 30$ ; GE = yes, O.K. JMP ERR5 ; Repport an syntax error 30$: SUB #'0,R2 ; Change symbol to numeric value ASL R1 ; Multiply ASL R1 ; the previous value ASL R1 ; by eight ADD R2,R1 ; Add current value BIT #400,R1 ; Byte owerflow? BEQ 15$ ; EQ = no, take next char. JMP ERR7 ; Report an error 35$: TST R1 ; Any nonzero output specified? BEQ 15$ ; EQ = no, skip this space 40$: MOVB R1,(R0)+ ; Put a byte to output buffer BR 10$ ; Repeat 50$: MOVB R1,(R0)+ ; Insert current byte to buffer SUB OUTCMD,R0 ; Compute output buffer length QIOW$S #IO.WLB!TF.WAL,#LUN,#1,,,, BCS 60$ ; If CS error 55$: EXST$S #EX$SUC ; Successfull exit 60$: EXST$S #EX$SEV ; Severe error ; .END