.TITLE CC001 ;Rsx version .ident /X01.20/ .NLIST BEX .ENABL LC, GBL .LIST MEB ; ; C COMPILER ; PREPROCESSOR ; ; VERSION X01 ; ; DAVID G. CONROY 17-JAN-78 ; ; EDIT HISTORY ; 01 7-May-79 MM Defined library as C: instead of LB:[1,1] ; 02 25-May-79 MM Added Ifdef/Ifndf/else/endif processing ; 03 29-May-79 MM Added undef processing ; 04 31-Jul-79 MM Added RT11 support ; 05 24-Sep-79 MM Fixed a stupid bug in RT11 #include processing ; 06 11-Jan-80 MM Pre-insert some definitions ; 07 18-Mar-80 MM Added #line, fixed another RT11 bug ; 08 07-May-80 MM Added #ifndef as an alternative to #ifndf ; 09 02-Jun-80 MM Fixed bug with pre-insertion ; 10 26-Feb-81 MM Added #define _DATE "foo" ; 11 10-Jul-81 JSL Allow #defines to have '$' ; 12 11-Feb-82 MM Floating point lives. ; 13 23-Mar-82 MM #define L xx ... long foo = 012L shouldn't expand. ; 14 02-Apr-82 MM Comments aren't nested anymore. Also, non terminated ; strings within #ifdef blocks are error'ed out. ; 15 15-Apr-82 MM Added c_rsts and c_vms ; 16 20-Apr-82 MM Fixed error message for ;14 ; 17 06-May-82 MM Bug in dodef, for #define _DATE "foo" ; 18 25-May-82 MM Better error message for ;16 ; 19 25-Nov-82 MM Added support for #if, larger buffer size. ; 20 27-Dec-82 MM Globalized OKSID and OKID for CC002 ; Make initial definitions non-zero ; ; The following definitions are pre-inserted: ; ; _DATE Compilation date as a quoted string ; decus The Decus (Conroy) compiler ; nofpu No floating-point support (for now) -- removed ;12 ; nomacarg No macros with arguments (for now) ; pdp11 Runs on a PDP-11 (or in compatibility mode) ; rsts If the rsts compiler - set by -r ; rsx If the rsx-11 compiler ; rt11 If the rt-11 compiler ; c_rsts If the compiler is running on rsts ; c_vms If the compiler is running on vms ; .GLOBL CCPREP .GLOBL IFFAIL ;ERROR ROUTINE FOR EVALUATOR ;19 .GLOBL SPNOR ;SKIP WHITESPACE ;19 .GLOBL OKSID ;TEST "START OF ID" ;20 .GLOBL OKID ;TEST "IN ID" ;20 .IF NE RSX ;04 .MCALL CALL .MCALL CALLR .MCALL RETURN .MCALL GET$S .MCALL PUT$S .MCALL CSI$ .MCALL CSI$1 .MCALL CSI$2 .MCALL OFNB$R .MCALL CLOSE$ CSI$ .IFF ;04 + .MACRO CALL ARG1,ARG2 .IF B ARG2 JSR PC,ARG1 .IFF JSR ARG1,ARG2 .ENDC .ENDM CALL .MACRO CALLR ARG1 JMP ARG1 .ENDM .MACRO RETURN ARG1 .IF B ARG1 RTS PC .IFF RTS ARG1 .ENDC .ENDM RETURN .MCALL .CSISPC, .FETCH, .LOOKUP, .CLOSE .ENDC ;04 - ; ; EQUIVALENCES ; DEFINE MACRO BLOCK ; LINK = 0 ;LINK TO NEXT MACRO REPLEN = 2 ;SIZE OF TEXT NAME = 4 ;START OF 8 BYTE NAME BODY = NAME+8. ;START OF BODY BLANK = 40 ;ASCII BLANK TAB = 11 ;ASCII TAB ; ; LOCAL DATA ; .PSECT LD001,OVR,GBL ;04 INCOM: .WORD 0 ;IN A COMMENT COUNT INCOS: .WORD 0 ;IN A CHAR CONSTANT OR STRING LINE: .WORD 0 ;LINE NUMBER DEFS: .WORD 0 ;HEAD OF MACRO TABLE FILE: .WORD P0IN ;POINTER TO SOURCE FDB BEND: .BLKW 1 ;POINTER TO RECORD END DELIM: .BLKW 1 ;DELIMITER FOR INCOS STLINE: .BLKW 1 ;SAVE FOR LINE NUMBER WHILE INCLUDING FLSLVL: .WORD 0 ;IF FALSE COUNTER ;02 TRULVL: .WORD 0 ;IF TRUE COUNTER ;02 CMDFLG: .BLKW 1 ;COMMAND PROCESSING TEMP ;02 SPSAVE: .BLKW 1 ;SAVES STACK FOR #IF EVALUATOR ;19 EVERR: .BLKW 1 ;SET NON-ZERO IF EVALUATOR DIES ;19 .if ne rsx ; ; RSX11-M specific globals and macro definitions ; .mcall GTSK$S ; ISRSTS = 4 ; Returned by GTSK$ for RSTS ISVMS = 5 ; Returned by GTSK$ for VMS ISMPLUS = 6 ; Returned by GTSK$ for RSX-11M+ tskbuf: .blkw 16. ; Task parameter buffer .iff ; ; RT11 specific macros and equivalences ; .mcall .gval ; ; Define RT11 file stuff ; Note: the format of the file data block was defined in CC0RT. ; INCCSI: .BLKW 39. ;CSI COMMAND BLOCK FOR FILE NAME INCBLK = INCCSI+<3*5*2> ;WHERE DEVBLK IS IN INCCSI .WORD INCBLK ;DEFINE FDB P0TMP: .WORD INC$CH ;ON CHANNEL (NUMBER DEFINED IN CC0RT) .WORD 0 .WORD 0 .WORD 0 .BLKB 512. .ENDC ;04 - .IIF NDF SIZ.IB SIZ.IB = 300. ;19 IDBUF: .BLKB 8. ;ID BUFFER TBUF: .BLKB SIZ.IB+30. ;TEMP. BUFFER ;19 BUF: .BLKB SIZ.IB ;RECORD BUFFER ;19 .PSECT ER001 DEF: .BYTE 144,145,146,151 ;DEFINE IN LOWER CASE ;02 + .BYTE 156,145,000,000 ; INC: .BYTE 151,156,143,154 ;INCLUDE IN LOWER CASE .BYTE 165,144,145,000 ; IFD: .BYTE 151,146,144,145 ;IFDEF IN LOWER CASE .BYTE 146,000,000,000 ; IFNDF: .BYTE 151,146,156,144 ;IFNDF IN LOWER CASE ;08 + .BYTE 146,000,000,000 ; IFNDEF: .BYTE 151,146,156,144 ;IFNDEF IN LOWER CASE .BYTE 145,146,000,000 ; ;08 - IF: .BYTE 151,146,000,000 ;IF IN LOWER CASE ;19 .BYTE 000,000,000,000 ; ;19 IFEND: .BYTE 145,156,144,151 ;ENDIF IN LOWER CASE .BYTE 146,000,000,000 ; IFELSE: .BYTE 145,154,163,145 ;ELSE IN LOWER CASE .BYTE 000,000,000,000 ; UND: .BYTE 165,156,144,145 ;UNDEF IN LOWER CASE .BYTE 146,000,000,000 ; ;02 - LIN: .BYTE 154,151,156,145 ;LINE IN LOWER CASE ;07 .BYTE 000,000,000,000 ; ;07 BLN: .ASCII " " ;FOR OUTPUT OF A BLANK LINE SYSINC:: ;GLOBALIZE DIRECTORY NAME ;01 .ASCIZ "LB0:[1,1]" ;SYSTEM INCLUDE DIRECTORY ;01 .ASCIZ " " ;GET SPACE FOR TKB PATCHES ;01 PREDEF: .ASCIZ "decus 1" ;THESE ARE #DEFINED AT STARTUP ;06+/20+ .ASCIZ "pdp11 1" .ASCIZ "nomacarg 1" .IF EQ RSX .ASCIZ "rt11 1" .IFF .ASCIZ "rsx 1" .ENDC .ASCIZ "" ;END OF DEFINITION LIST ;06- PRRSTS: .ASCIZ "c_rsts 1" ;If the compiler is running ;15 PRVMS: .ASCIZ "c_vms 1" ;emulated ;15 IFRSTS: .ASCIZ "rsts 1" ;-r switch ;15/20- ERR01: .ASCIZ "I/O error on input" ERR02: .ASCIZ "I/O error on output" ERR03: .ASCIZ "Line overflow" ERR04: .ASCIZ "Nested includes not permitted" ERR05: .ASCIZ "Illegal control line" ERR06: .ASCIZ "Cannot open include file" ERR07: .ASCIZ "Illegal comment in define" ERR08: .ASCIZ "Too few #ifdef - else found" ERR09: .ASCIZ "Too few #ifdef - endif found" ERR10: .ASCIZ "#undef object undefined" ERR11: .ASCIZ "Inside #ifdef block at end. Depth = " ERR12: .ASCIZ "Non-terminated string or character constant." ;16/18 ERR13: .ASCIZ /#if parse stopped at "/ ;19 ERR14: .ASCIZ // .EVEN ;+ ; ** $MAIN - PREPROCESSOR MAINLINE ; ; THIS IS THE MAIN LOOP OF THE PREPROCESSOR. IT IS CALLED FROM CC000 ; WITH A TEMP FILE OPEN (FOR WRITING) ON P0OUT, AND THE ORIGINAL USER ; SOURCE OPEN FOR READING ON P0IN (P0IN WILL EVENTUALLY BE REUSED AS ; THE ASM OUTPUT FDB, WHERE IT WILL BE CALLED P2OUT). ; ; THIS ROUTINE READS THE SOURCE, PERFORMING THE REQUIRED DEFINES AND ; INCLUDES, AND WRITING THE WHOLE LOT TO THE TEMP FILE. ;- ;DEBUG+ ;IN...: .ASCII "Input :" ; .BYTE 200 ;OUT...: .ASCII "Output :" ; .BYTE 200 ; .EVEN ;DEBUG- .PSECT CC001 ;04 ; ; LOAD PREDEFINED STUFF ;06+ ; CC001:: ;04 CCPREP: MOV #DATDEF,R1 ;#define _DATE ;10+;11;15 CALL DODEF ;DO IT ;15 MOV #PREDEF,R1 ;START OF PREDEFINED BUFFER 10$: TSTB (R1) ;AT THE END? BEQ 20$ ;YES, START THE REAL STUFF CALL DODEF ;DEFINE IT ;15 BR 10$ ;GET ANOTHER 20$: ; ;15+ ; Define rsts if -r switch, then c_rsts or c_vms ; TSTB RFLAG ;-R REQUESTED BEQ 30$ ;NO, CONTINUE MOV #IFRSTS,R1 ;YES, DO IT CALL DODEF 30$: .if ne rsx ;15+ ; ; Do a get task to get the task name and default UIC ; GTSK$S #tskbuf ;Get task parameters mov tskbuf+G.TSSY,#ISRSTS ;Op. system unique code bne 40$ ;Not today mov #prrsts,r1 ;yep call dodef 40$: ; cmp tskbuf+G.TSSY,#ISVMS ;VMS? bne 50$ ;No mov #prvms,r1 ;Yep call dodef 50$: .iff ; ; RT11 specific code: set lower-case bit, check if it's really RSTS/E ; emulation. Then do an incredable hack on RSTS to find the command line. ; cmp -(sp),-(sp) ; Get temp for .gtval mov sp,r1 ; R1 -> .gtval pmtr. block ; ; Note: someday, we may have to test for RT11 emulation on vms, too. ; .gval r1,#0 ; Get first word of RMON cmp (sp)+,(sp)+ ; Clean the stack tst r0 ; It's non-zero on native RT11 bne 40$ ; Br if native mov #prrsts,r1 ; do it call dodef ; 40$: .endc ;15- CLR LINE ;NO LINES READ YET ;06 - CALL SHARP ;OUTPUT A # 0 TO FIX PASS 1 ;09 PRLOOP: MOV #SIZ.IB,-(SP) ;PUSH MAXIMUM LINE LENGTH ;04+;19 MOV #BUF,-(SP) ;AND BUFFER START MOV FILE,R0 ;R0 -> CURRENT INPUT FILE CALL RDLINE ;GO GET A LINE BIT (SP)+,(SP)+ ;CLEAR STACK, LEAVE C-BIT ALONE ;04 - BCS 30$ ;ERROR, MIGHT BE EOF INC LINE ;UPDATE LINE NUMBER MOV #BUF,BEND ;COMPUTE THE ADDRESS OF THE ADD R0,BEND ;END OF THE RECORD ;04 CLRB @BEND ;MARK BYTE PAST END FOR EVAL ;19 ;DEBUG+ ; .MCALL .PRINT ; .PRINT #IN... ; .PRINT #BUF ;DEBUG- CMPB BUF,#'# ;IS IT A CONTROL LINE BNE 20$ ;NO TST INCOS ;IN CHAR. CONSTANT OR STRING BNE 20$ ;IF SO, NOT A CONTROL LINE TST INCOM ;IN A COMMENT BNE 20$ ;IF SO, NOT A CONTROL LINE CALL CONTRL ;PROCESS CONTROL LINE BR PRLOOP ;AND GO FOR MORE 20$: TST FLSLVL ;ACTUALLY COMPILING? ;02 + BEQ 25$ ;YES CALL PUTBLN ;NO, OUTPUT A BLANK LINE BR PRLOOP ;AND DO ANOTHER ;02 - 25$: CALL EXPAND ;EXPAND ANY MACROS ;DEBUG+ ; CLRB @BEND ; .PRINT #OUT... ; .PRINT #BUF ;DEBUG- MOV BEND,R1 ;COMPUTE RECORD SUB #BUF,R1 ;SIZE MOV R1,-(SP) ;PUSH NUMBER OF BYTES TO OUTPUT ;04 + MOV #BUF,-(SP) ;PUSH BUFFER ADDRESS MOV #P0OUT,R0 ;GET FILE DATA BLOCK CALL PUTTXT ;WRITE IT OUT BIT (SP)+,(SP)+ ;CLEAR STACK, LEAVE C-BIT ALONE ;04 - BCC PRLOOP ;AND GO FOR MORE MOV #ERR01,R0 ;I/O ERROR ON OUTPUT JMP CCABRT ;DIE 30$: TST R0 ;IS THE ERROR "END OF FILE" ;04 BEQ 40$ ;YES MOV #ERR02,R0 ;I/O ERROR ON INPUT JMP CCABRT ;DIE 40$: CMP FILE,#P0IN ;IS THE FILE STANDARD INPUT BEQ 50$ ;YES .IF NE RSX ;04 CLOSE$ FILE ;NO, CLOSE THE INCLUDE FILE .IFF ;04 .CLOSE #INC$CH ;AND CLOSE THE FILE ;04 .ENDC ;04 MOV #P0IN,FILE ;SET FILE TO STANDARD INPUT MOV STLINE,LINE ;BACK UP LINE NUMBER CALL SHARP ;OUTPUT A SHARP RECORD AND BR PRLOOP ;GO BACK FOR MORE 50$: MOV TRULVL,R2 ;CHECK IF DEPTH ;02 + ADD FLSLVL,R2 ;BOTH SHOULD BE ZERO BEQ 70$ ;NO PROBLEMS MOV #TBUF,R1 ;TROUBLE, GET TEMP BUFFER MOV LINE,R0 ;PRINT LINE NUMBER CALL $ITOC MOVB #'#,(R1)+ ;WITH SOME COMMENTARY MOVB #' ,(R1)+ ;AND A SPACE MOV #ERR11,R0 ;AND AN ERROR MESSAGE 60$: MOVB (R0)+,(R1)+ ;ALL THE BYTES, BNE 60$ ;PLEASE. DEC R1 ;Back up over the trailing null ;14 MOV R2,R0 ;RECOVER DEPTH CALL $ITOC ;INTO THE BUFFER CLRB (R1)+ ;TERMINATOR MOV #TBUF,R0 ;GET ERROR LINE AND CALL CCERR ;PRINT THE ERROR MESSAGE INC NERRS ;IT'S A PROBLEM ;02 - ; 70$: MOV #P0OUT,R0 ;CLEAN UP THE LAST BUFFER ;04 CALLR FLUSH ;SO RT11 READS OK ;04 ;FLUSH RETURNS TO MAINLINE ;04 ;+ ;15+ ; ** DODEF ; ; DEFINE A STRING ; ; INPUT: ; R1 -> ASCIZ STRING (foo) ; ; OUTPUT: ; R1 -> BYTE FOLLOWING NULL TRAILER OF ARG. STRING ; Generates: ; #define foo ; ; USES R0,R5, BUF, BEND, AND WHATEVER ELSE CONTRL USES ;- DODEF: MOV #BUF,R5 ;POINT TO WORK BUFFER MOV #DEF,R0 ;POINT TO "DEFINE" MOVB #'#,(R5)+ ;CREATE A "#define " STRING 20$: MOVB (R0)+,(R5)+ ;COPY IN DEFINE BNE 20$ ;ALL OF IT MOVB #' ,-1(R5) ;THEN A BLANK 30$: MOVB (R1)+,(R5)+ ;NOW, MOVE IN THE WORD BNE 30$ ;TO BE DEFINED DEC R5 ;DON'T INCLUDE TRAILING NULL ?? ;17 MOV R5,BEND ;SAVE THE LENGTH MOV R1,-(SP) ;SAVE THE PREDEFINED BUFFER PTR CALL CONTRL ;DO A CONTROL LINE MOV (SP)+,R1 ;RECOVER PREDEFINED PTR RETURN ;AND EXIT ;15- ;DEBUG+ ;DB001: .ASCIZ "Up true counter" ;DB002: .ASCIZ "Up false counter" ;DB003: .ASCIZ "Endif drops false counter" ; .EVEN ;DEBUG- ;+ ; ** CONTRL - PROCESS CONTROL LINES ; ; THIS ROUTINE IS CALLED WHENEVER A CONTROL LINE IS ENCOUNTERED IN THE ; INPUT. ; ; INPUTS: ; BUF=THE RECORD ; BEND=POINTER TO THE END OF THE RECORD ;- CONTRL: MOV #BUF+1,R5 ;POINT JUST PAST THE '#' CALL SPNOR ;SKIP BLANKS BCS 4$ ;IGNORE BLANK LINES ;02 CLR CMDFLG ;INITIALIZE COMMAND TEST ;02 CALL GETID ;GET TYPE MOV #IFD,R0 ;TEST FOR ;02 + CALL EQUAL ;IFDEF BCC 140$ ;GO FOR IT MOV #IFNDF,R0 ;TEST FOR CALL EQUAL ;IFNDF BCC 132$ ;YES, GO FOR IT ;08 + MOV #IFNDEF,R0 ;NO, TEST FOR CALL EQUAL ;IFNDEF ;08 - BCC 132$ ;GO FOR IT ;19+ MOV #IF,R0 ;NO, TEST FOR CALL EQUAL ;IF BCS 1$ ;NO, TRY NEXT CLR EVERR ;EVAULATE #IF EXPRESSION, CLEAR ERROR MOV R5,-(SP) ;SAVE POSITION IN INPUT LINE CALL EXPND1 ;AND EXPAND ANY MACRO'S MOV (SP)+,R5 ;RESET POSITION IN LINE TST EVERR ;PROBLEM IN EXPANSION? BNE 210$ ;YES, JUMP OUT. MOV SP,SPSAVE ;SAVE STACK FOR ERROR EXIT FROM EVAL CALL IFEVAL ;AND EVALUATE #IF EXPRESSION TST EVERR ;PROBLEM? BEQ 220$ ;NO, NORMAL EXIT. 210$: JMP 130$ ;YES, TAKE ERROR EXIT. 220$: TST R2 ;RESULT FROM EVAL, 0 == FALSE, 1 == TRUE BNE 141$ ;TRUE BR 154$ ;FALSE ;19- 132$: INC CMDFLG ;IFNDF SEEN, WANT C-BIT SET FROM LOOKUP ; ; #Ifdef/ifndf processing ; 140$: TST FLSLVL ;COMPILE IT? BNE 154$ ;BRANCH IF NOT CALL SPNOR ;SKIP OVER WHITE SPACE BCS 158$ ;TROUBLE IF NONE CALL OKSID ;MUST BE A BCS 158$ ;LEGAL ID CALL GETID ;GET THE IDENTIFIER CALL LOOKUP ;LOOK FOR THE VARIABLE BIC R0,R0 ;GET RETURN (C-BIT) INTO R0 ROL R0 ;R0 := 0 IF FOUND, 1 IF NOT FOUND CMP CMDFLG,R0 ;IF THEY'RE THE SAME, THE TEST SUCCEEDS BNE 154$ ;BRANCH IF IF FAILS 141$: ;TRUE TEST (FROM #IF EVALUATOR) ;19 INC TRULVL ;INCREMENT TRUE COUNTER ;DEBUG+ ; .MCALL .PRINT ; .PRINT #DB001 ;DEBUG- BR 4$ ;AND GO TO EXIT 154$: INC FLSLVL ;TURN OFF COMPILATION ;DEBUG+ ; .PRINT #DB002 ;DEBUG- BR 4$ ;AND EXIT, PRINTING A BLANK LINE 158$: JMP 100$ ;TROUBLE EXIT 1$: MOV #IFELSE,R0 ;TEST FOR CALL EQUAL ;ELSE BCS 2$ ;NO, TRY NEXT ; ; #else Processing ; TST FLSLVL ;SKIPPING COMPILING? BEQ 164$ ;IF SO, GO TRY TRUE COUNT DEC FLSLVL ;YES, DROP FALSE COUNT BEQ 162$ ;MAKE IT TRUE IF ZERO NOW INC FLSLVL ;NO, KEEP IT FALSE BR 4$ ;AND EXIT 162$: INC TRULVL ;KEEP "INSIDE IF BLOCK" COUNT BR 4$ ;AND GO EXIT 164$: TST TRULVL ;FALSE WAS ZERO. ARE WE INSIDE AN IF? BNE 166$ ;YES, KEEP ON TRUCKING MOV #ERR08,R0 ;NO, TROUBLE JMP 120$ ;EXIT WITH AN ERROR MESSAGE 166$: INC FLSLVL ;ELSE MAKES IT FALSE DEC TRULVL ;THUS, IT CAN'T BE TRUE BR 4$ ;AND EXIT 2$: MOV #IFEND,R0 ;TEST FOR CALL EQUAL ;ENDIF BCS 3$ ;NO, TRY NEXT ; ; #endif Processing ; TST FLSLVL ;INSIDE A NON-COMPILE BLOCK? BEQ 172$ ;BRANCH IF NOT. ;DEBUG+ ; .PRINT #DB003 ;DEBUG- DEC FLSLVL ;ONE LESS FALSEHOOD BR 4$ ;GO TO COMMON EXIT 172$: TST TRULVL ;NOT FALSE, IS IT TRUE? BEQ 176$ ;IF NOT, GO TO TROUBLE DEC TRULVL ;DROP IF BLOCK COUNTER BR 4$ ;GO TO COMMON EXIT 176$: MOV #ERR09,R0 ;END WITHOUT MATCHING IF JMP 120$ ;TAKE ERROR EXIT ;02 - 3$: TST FLSLVL ;COMPILING NOW? BEQ 5$ ;BRANCH IF SO 4$: JMP 65$ ;PUT OUT A BLANK LINE ;03 + 5$: MOV #DEF,R0 ;TEST FOR CALL EQUAL ;DEFINE BCC 6$ ;BR IF SO INC CMDFLG ;MARK IT "UNDEFINED" MOV #UND,R0 ;TEST FOR CALL EQUAL ;UNDEFINED BCC 6$ ;BRANCH IF SO JMP 70$ ;NO, TRY NEXT ;03 - ; ; #define/undef processing ; 6$: CALL SPNOR ;SKIP TO MACRO NAME BCS 66$ ;NO NAME CALL OKSID ;MUST BE A BCS 66$ ;LEGAL ID CALL GETID ;GET THE NAME AND CALL LOOKUP ;LOOK IT UP BCC 8$ ;GOT IT ;03 + TST CMDFLG ;NOT THERE, DEFINING IT? BEQ 30$ ;YES, DO SO JMP 130$ ;CAN'T UNDEFINE NOTHING ;03-, 06 8$: MOV #DEFS,R1 ;SEARCH FOR THE ITEM 10$: CMP (R1),R0 ;THAT IS BEFORE THE ITEM IN BEQ 20$ ;QUESTION MOV (R1),R1 ;FOLLOW LINKS BNE 10$ ;IT CRASH ;MUST BE THERE 20$: MOV (R0),(R1) ;UNLINK THE ITEM IN QUESTION CALL $FREE ;FREE IT TST CMDFLG ;UNDEFINING? ;03 BEQ 30$ ;NO, DO DEFINE ;03 JMP 65$ ;YES, ALL DONE. ;03 30$: CALL SPNOR ;SKIP TO THE START BCS 32$ ;OF THE MACRO AND DEC R5 ;POINT R5 AT IT 32$: MOV R5,R4 ;SET UP TO MOV R5,R3 ;COMPRESS THE MACRO CLR R2 ;ZERO COMMENT DEPTH 34$: CMP R3,BEND ;BREAK LOOP IF BHIS 42$ ;DONE MOVB (R3)+,R0 ;PICK UP SOURCE CHARACTER TST R2 ;ARE WE IN A COMMENT BEQ 38$ ;NO CMP R3,BEND ;IS THERE ANOTHER CHARACTER BHIS 34$ ;NO .if ne 0 ;Comments aren't nested now ;14 CMPB R0,#'/ ;CHECK IF BNE 36$ ;ENTERING CMPB (R3),#'* ;ANOTHER BNE 34$ ;COMMENT AND INC R2 ;INCREASE DEPTH AND INC R3 ;SKIP THE '*' IF BR 34$ ;YES .endc ;14 36$: CMPB R0,#'* ;CHECK IF LEAVING BNE 34$ ;A COMMENT CMPB (R3),#'/ ;AND BNE 34$ ;DECREASE DEPTH DEC R2 ;AND INC R3 ;SKIP THE '/' IF BR 34$ ;YES 38$: CMPB R0,#'/ ;TEST IF BNE 40$ ;ENTERING CMP R3,BEND ;A BHIS 40$ ;COMMENT CMPB (R3),#'* ;AND BNE 40$ ;INCREASE INC R2 ;DEPTH AND INC R3 ;SKIP OVER THE '/*' IF BR 34$ ;YES 40$: MOVB R0,(R4)+ ;SAVE BYTE INTO THE BR 34$ ;COMPRESSED LINE 42$: TST R2 ;DID THE COMPRESS END IN A COMMENT BEQ 44$ ;NO MOV #ERR07,R0 ;YES CALL ERROR0 ;COMPLAIN 44$: CMP R4,R5 ;DELETE TRAILING WHITE SPACE BLOS 46$ ;FROM MOVB -(R4),R0 ;THE CMP R0,#BLANK ;MACRO BEQ 44$ ;BODY CMP R0,#TAB ;TO BEQ 44$ ;AVOID INC R4 ;LINE OVERFLOW 46$: MOV R4,BEND ;COMPUTE SUB R5,R4 ;LENGTH OF THE BODY MOV R4,R0 ;THEN GET ADD #BODY,R0 ;SPACE FOR THE CALL $ALLOC ;MACRO BLOCK MOV DEFS,(R0) ;LINK MOV R0,DEFS ;INTO TST (R0)+ ;LIST MOV R4,(R0)+ ;REPLEN MOV #IDBUF,R1 ;COPY 50$: MOVB (R1)+,(R0)+ ;IN CMP R1,#IDBUF+8. ;THE BLO 50$ ;NAME 60$: CMP R5,BEND ;COPY BHIS 65$ ;IN MOVB (R5)+,(R0)+ ;THE BR 60$ ;BODY 65$: CALL PUTBLN ;PUT OUT A BLANK LINE SO JMP 130$ ;THE LINENUMBERS ARE CORRECT 66$: JMP 100$ ;ILLEGAL CONTROL LINE 70$: MOV #INC,R0 ;TEST FOR CALL EQUAL ;INCLUDE BCS 95$ ;BR IF NOT ; ; #include processing ; CMP FILE,#P0IN ;ARE WE IN AN INCLUDE BEQ 80$ ;NO MOV #ERR04,R0 ;YES, GIVE BR 120$ ;DIAGNOSTIC 80$: CALL SPNOR ;SKIP TO THE BCS 100$ ;FILE NAME MOV #TBUF,R1 ;POINT AT TEMP NAME BUFFER MOV #'",DELIM ;ASSUME ORDINARY INCLUDE CMP R0,#'" ;IS IT BEQ 90$ ;YES MOV #'>,DELIM ;ASSUME SYSTEM INCLUDE CMP R0,#'< ;IS IT BNE 100$ ;NO MOV #SYSINC,R2 ;COPY IN "C:" (OR WHATEVER) ;01 82$: MOVB (R2)+,(R1)+ ; BNE 82$ ; DEC R1 ;BACK UP OVER THE NULL 90$: CMP R5,BEND ;NOW LOOK FOR THE BHIS 100$ ;END OF THE NAME MOVB (R5)+,R0 ;GRAB CHARACTER FROM NAME CMP R0,DELIM ;IS IT THE DELIMITER BEQ 92$ ;YES CMPB R0,#'a ;IS IT LOWER CASE BLO 91$ ;NO CMPB R0,#'z ; BHI 91$ ;NO BICB #' ,R0 ;FORCE TO UPPER 91$: MOVB R0,(R1)+ ;SAVE IN BUFFER AND BR 90$ ;CONTINUE 92$: .IF NE RSX ;04 SUB #TBUF,R1 ;COMPUTE FILE NAME LENGTH MOV R1,CSI+C.CMLD ;SAVE IT MOV #TBUF,CSI+C.CMLD+2 ;ALSO SAVE FILE NAME ADDRESS CSI$1 #CSI ;PARSE THE BCS 110$ ;FILE CSI$2 ,OUTPUT ;USING THE BCS 110$ ;DREADED CSI MOV #P0TMP,R0 ;OPEN MOV #P0TMP+F.FNB,R1 ;THE MOV #CSI+C.DSDS,R2 ;HARD WAY MOV #DFNB1,R3 ;SO THAT CALL .PARSE ;NO EXTRA BCS 110$ ;STUFF OFNB$R ;GETS BCS 110$ ;LOADED .IFF ;04 + CLRB (R1) ;TERMINATE THE STRING ;05 .CSISPC #INCCSI,#DEFEXT,#TBUF ;PARSE THE FILE NAME BCS 110$ ;DIE ON ERROR MOV (SP)+,R0 ;ANY SWITCHES? BEQ 93$ ;NO, GOOD FOR HIM ASL R0 ;YES, TRASH THE STACK ADD R0,SP ;TO REMOVE SWITCH STUFF BR 110$ ;AND DIE TWITCHING 93$: ; Note: The fetch is not taken so as not to disturb free memory. ; the moral of the story is that all #include devices must have ; their handlers' pre-loaded (or loaded by the open of the main files. ; .FETCH @#50,#INCBLK ;FETCH THE HANDLER ; BCS 110$ ;DIE IF CAN'T FETCH IT .LOOKUP #INCCSI,#INC$CH,#INCBLK BCS 110$ ;DIE IF IT WON'T OPEN .IFTF ;04 - MOV LINE,STLINE ;SAVE LINE NUMBER CLR LINE ;RESET LINE NUMBER MOV #P0TMP,FILE ;RESET FILE NAME ;04 .IFF ;04 + CLR P0TMP+FDB$NF ;MAKE SURE THE FDB IS CLR P0TMP+FDB$FP ;EMPTY IN PREPARATION FOR CLR P0TMP+FDB$BL ;THE FIRST READ .ENDC ;04 - CALL SHARP ;OUPUT '#' RECORD BR 130$ ;DONE 95$: MOV #LIN,R0 ;IS IT LINE NUMBER? ;07 + CALL EQUAL ;GO FOR IT BCS 100$ ;BRANCH IF NOT ; ; #line processing ; CALL SPNOR ;SKIP OVER WHITESPACE BCS 96$ ;HACK EXIT IF EMPTY DEC R5 ;R5 -> FIRST NON-WHITE CHAR. CMPB R0,#'0 ;#LINE 012 BLO 96$ ;NO CMPB R0,#'9 ;#LINE 999 BLOS 97$ ;YES ; 96$: MOVB #' ,-(R5) ;FIX THE LINE MOVB #'0,-(R5) ;SO PASS 1 ACCEPTS IT ; 97$: MOVB #'#,-(R5) ;PRECEEDED BY A SHARP MOV BEND,-(SP) ;RECORD END POINTER SUB R5,(SP) ;NOW IT'S RECORD LENGTH MOV R5,-(SP) ;HERE'S THE RECORD MOV #P0OUT,R0 ;AND THE FILE CALL PUTTXT ;GO FOR IT BIT (SP)+,(SP)+ ;CLEAR THE STACK BR 130$ ;AND GO TO COMMON EXIT ;07- 100$: MOV #ERR05,R0 ;ILLEGAL CONTROL LINE BR 120$ ; 110$: MOV #ERR06,R0 ;CONNOT OPEN FILE 120$: CALL ERROR0 ;COMPLAIN 130$: RETURN ;FINIS ;+ ;19 ; ** IFFAIL -- FAILURE EXIT FROM #IF EVAULATOR ; ; JUMP HERE TO ABORT FROM THE RECURSIVE DESCENT EVALUATOR PARSER. ; ; INPUTS: ; R0=ERROR MESSAGE IFFAIL: INC EVERR ;SET ERROR CODE CALL ERROR0 ;PRINT ERROR MESSAGE. MOV #ERR13,R0 ;"Parse stopped at..." MOV #TBUF,R1 ;BUFFER 10$: MOVB (R0)+,(R1)+ ;WRITE IT OUT BNE 10$ ;ALL OF IT DEC R1 ;BACK UP OVER EOS. MOV R5,R0 ;NEXT BYTE TO SCAN CMP R5,BEND ;WERE WE AT THE END ALREADY? BLO 20$ ;NO, CONTINUE NORMALLY MOV #ERR14,R0 ;YES, PUT OUT A SPECIAL. 20$: MOVB (R0)+,(R1)+ ;WRITE IT OUT BNE 20$ ;TILL EOS MOVB #'",(R1)+ ;TERMINATE TEXT CLRB (R1) ;TERMINATE STRING MOV #TBUF,R0 ;PRINT THIS BUFFER CALL CCERR ;PRINT IT MOV SPSAVE,SP ;RETURN TO EVAL CALLER RETURN ;UNWINDING THE STACK ;19- ;+ ; ** EXPAND - EXPAND OUT MACROS ; ; THIS ROUTINE IS CALLED FOR ANY NON CONTROL LINES ENCOUNTERED IN THE ; INPUT. IT SEARCHES THE LINE FOR ANY IDENTIFIERS THAT HAVE BEEN SET ; UP AS MACROS VIA A DEFINE CONTROL LINE, AND EXPANDS THEM. ; ; INPUTS: ; BUF=THE RECORD (EXPAND) ; R5=THE RECORD (EXPND1) (R5 USED) ; BEND=POINTER TO THE END OF THE RECORD ;- EXPAND: MOV #BUF,R5 ;POINT AT THE START EXPND1: ;HERE TO EVALUATE FROM MID-LINE ;19 10$: CMP R5,BEND ;BREAK LOOP IF BLO 12$ ;ALL DONE TST INCOS ;Still in a string? ;14+ BEQ 11$ ;No, continue CLR INCOS ;Clear flag so errors don't cascade INC EVERR ;Error for evaluator ;19 MOV #ERR12,R0 ;In a string at end of line CALL ERROR0 ;Complain about it 11$: ;Br here if line ends with backslash ;14- JMP 170$ ;DONE WITH THIS LINE 12$: MOVB (R5)+,R0 ;GET CHARACTER FROM LINE TST INCOS ;ARE WE IN CHAR CONST OR STRING BEQ 30$ ;BR IF NOT CMPB R0,DELIM ;LEAVING? BNE 20$ ;NO DEC INCOS ;LEAVE STRING OR CHAR CONST BR 10$ ;MODE 20$: CMPB R0,#'\ ;ESCAPE SEQUENCE? BNE 10$ ;NO CMP R5,BEND ;AT THE END BHIS 11$ ;YES -- Don't check for "in a string" ;14 INC R5 ;SKIP NEXT CHARACTER BR 10$ ; 30$: TST INCOM ;IN A COMMENT BEQ 50$ ;BR IF NOT CMP R5,BEND ;SEE IF THERE IS ANOTHER CHAR. BHIS 10$ ;NO .if ne 0 ; Comments don't nest now ;14 CMPB R0,#'/ ;IS IT A '/*' BNE 40$ ;NO CMPB (R5),#'* ;MAYBE BNE 10$ ;NO INC INCOM ;INCREASE COMMENT DEPTH INC R5 ;SKIP THE '*' BR 10$ ;AND GO AGAIN .endc ;14 40$: CMPB R0,#'* ;IS IT A '*/' BNE 10$ ;NO CMPB (R5),#'/ ;MAYBE BNE 10$ ;NO DEC INCOM ;DECREASE COMMENT DEPTH INC R5 ;SKIP THE '/' BR 10$ ;AND GO AGAIN 50$: CMPB R0,#'" ;ENTERING A STRING BEQ 52$ ;YES CMPB R0,#'' ;ENTERING A CHARACTER CONSTANT BNE 60$ ;NO 52$: MOV R0,DELIM ;SAVE WHICH INC INCOS ;SET IN STRING OR CHAR CONSTANT BR 10$ ;GO AGAIN 60$: CMPB R0,#'/ ;ENTERING A COMMENT BNE 70$ ;NO CMP R5,BEND ;PERHAPS BHIS 70$ ;NO CMPB (R5),#'* ;IS IT A '/*' BNE 70$ ;NO INC INCOM ;INCREASE COMMENT DEPTH INC R5 ;SKIP OVER THE '*' BR 10$ ;GO AGAIN 70$: CALL OKSID ;COULD THIS CHAR. START AN ID BCS 75$ ;NO ;13 MOV R5,-(SP) ;SAVE WHERE WE ARE CALL GETID ;GET THE ID CALL LOOKUP ;AND LOOK IT UP BCC 80$ ;FOUND IT TST (SP)+ ;OH WELL BR 10$ ;JUST CONTINUE 75$: CALL OKID ;BUT, IS IT A NUMERIC CONSTANT? ;13+ BCS 10$ ;NO, JUST CONTINUE CALL GETID ;YES, SKIP OVER IT SO #define L xxx WORKS BR 10$ ;BACK FOR MORE ;13- 80$: DEC (SP) ;POINT (SP) AT ID[0] MOV R5,R4 ;COMPUTE THE SUB (SP),R4 ;DELTA SIZE NEG R4 ;OF ADD #2,R4 ;THE NEW ADD REPLEN(R0),R4 ;LINE BEQ 140$ ;SAME SIZE BGT 110$ ;NEW LINE IS LONGER ADD R5,R4 ;NEW LINE IS SHORTER 90$: CMP R5,BEND ;SO SHIFT IT BHIS 100$ ;LEFT MOVB (R5)+,(R4)+ ;TO BR 90$ ;RIGHT 100$: MOV R4,BEND ;SET NEW END OF BUFFER CLRB (R4) ;AND FORCE TERMINATOR FOR DEBUGGING ;19 BR 140$ ;GO COPY IN TEXT 110$: ADD BEND,R4 ;NEW LINE IS LONGER CMP R4,#BUF+SIZ.IB ;IS THE LINE TOO LONG ;19 BLO 120$ ;NO INC EVERR ;SET FLAG FOR EVAULATOR ;19 MOV #ERR03,R0 ;COMPLAIN CALL ERROR0 ;ABOUT IT TST (SP)+ ;JUST FORGET ABOUT BR 10$ ;THIS ONE 120$: MOV BEND,R5 ;SET UP TO SLIDE THE MOV R4,BEND ;LINE RIGHT TO LEFT CLRB (R4) ;FORCE TERMINATOR FOR DEBUG PRINTOUTS ;19 130$: CMP R5,(SP) ;SEE IF DONE BLOS 140$ ;YES MOVB -(R5),-(R4) ;SLIDE THE BR 130$ ;LINE ALONG 140$: MOV (SP),R5 ;COPY IN MACRO BODY MOVB #' ,(R5)+ ;BLANK MOV REPLEN(R0),R4 ;SIZE OF REPLACEMENT TEXT BEQ 160$ ;NULL ADD #BODY,R0 ;R0 POINTS AT TEXT 150$: MOVB (R0)+,(R5)+ ;COPY DEC R4 ;THE BNE 150$ ;TEXT 160$: MOVB #' ,(R5) ;BLANK MOV (SP)+,R5 ;RESCAN THE TEXT JMP 10$ ;GO AGAIN 170$: RETURN ;FINIS ;+ ; ** GETID - READ AN ID INTO IDBUF ; ; INPUTS: ; R0=FIRST CHARACTER OF THE ID ; R5=POINTER INTO THE BUFFER ; ; USES: ; R1 ;- GETID: MOV #IDBUF,R1 ;POINT AT ID BUFFER 10$: CMP R1,#IDBUF+8. ;WILL IT FIT BHIS 20$ ;NO MOVB R0,(R1)+ ;YES, STORE IT 20$: CMP R5,BEND ;IS THERE A CHARACTER TO GET BHIS 30$ ;NO MOVB (R5)+,R0 ;YES, GET IT CALL OKID ;IS IT OK IN AN ID BCC 10$ ;YES DEC R5 ;PUT IT BACK 30$: CMP R1,#IDBUF+8. ;NOW PAD THE BHIS 40$ ;ID CLRB (R1)+ ;WITH BR 30$ ;NULLS 40$: RETURN ;DONE ;+ ; ** OKSID - TEST IF CHARACTER IS OK AT THE START OF AN ID ; ** OKID - TEST IF CHARACTER IS OK IN AN ID ; ; INPUTS: ; R0=CHARACTER ; ; OUTPUTS: ; C=0 IF OK, C=1 IF NOT ;- .ENABL LSB OKID: CMPB R0,#'0 ;TEST FOR NUMERICS BLO OKSID ;TOO LOW, BUT CHECK FOR $ ;11 CMPB R0,#'9 BLOS 20$ OKSID: CMPB R0,#'$ ;DOLLAR SIGN? ;07 BEQ 20$ ;OK NOW ;07 CMPB R0,#101 ;UPPER CASE ALPHABETICS BLO 10$ CMPB R0,#132 BLOS 20$ CMPB R0,#'_ ;UNDERBAR BEQ 20$ CMPB R0,#141 ;LOWER CASES ALPHABETICS BLO 10$ CMPB R0,#172 BLOS 20$ 10$: SEC ;NOT LEGAL BR 30$ 20$: CLC ;LEGAL 30$: RETURN .DSABL LSB ;+ ; ** SPNOR - SKIP BLANKS ; ; INPUTS: ; R5=POINTER TO NEXT CHARACTER IN BUFFER ; ; OUTPUTS: ; C=0 ; R0=FIRST NONBLANK CHARACTER ; R5=UPDATED ; ; C=1 IF THE LINE RAN OUT FIRST (R0 == EOS) ; If the line runs out, R5 will point beyond BEND so the ;19 ; unget code in the #if parser can "always" unget. ;19 ;- SPNOR: CMP R5,BEND ;TEST FOR LINE RUNOUT BHIS 10$ ; MOVB (R5)+,R0 ;GET CHARACTER CMPB R0,#BLANK ;SKIP BEQ SPNOR ;BLANKS CMPB R0,#TAB ;AND BEQ SPNOR ;TABS CLC ;GOOD RETURN BR 20$ ; 10$: MOV BEND,R5 ;RESET R5 TO ALLOW RECALLS. ;19+ INC R5 ;EVEN AFTER AN UNGET CLR R0 ;RETURN CONSISTANT VALUE ;19- SEC ;LINE RAN OUT 20$: RETURN ;FINIS ;+ ; ** LOOKUP - LOOKUP MACRO ; ; INPUTS: ; IDBUF=THE NAME ; ; OUTPUTS: ; R0=POINTER TO MACRO BLOCK ; ; USES: ; R1, R2 ;- LOOKUP: MOV DEFS,R0 ;GET HEAD OF THE MACRO TABLE BEQ 40$ ;NULL 10$: MOV R0,R1 ;R1=POINTER TO NAME ADD #NAME,R1 ; MOV #IDBUF,R2 ;R2=POINTER TO ID 20$: CMPB (R1)+,(R2)+ ;SEE BNE 30$ ;IF CMP R2,#IDBUF+8. ;THE NAMES BLO 20$ ;MATCH CLC ;FOUND IT BR 50$ ; 30$: MOV (R0),R0 ;CHAIN DOWN THE TABLE BNE 10$ ;STILL MORE 40$: SEC ;NOT FOUND 50$: RETURN ;FINIS ;+ ; ** ERROR0 - OUTPUT ERROR MESSAGES ; ; INPUTS: ; R0=POINTER TO ASCIZ MESSAGE ; ; USES: ; R0, R1 ;- ERROR0: MOV R0,-(SP) ;SAVE MESSAGE POINTER MOV #TBUF,R1 ;GET POINTER TO TEMP. BUFFER MOV LINE,R0 ;CONVERT CALL $ITOC ;LINE NUMBER MOVB #':,(R1)+ ;FOR MOVB #' ,(R1)+ ;LOOKS MOV FILE,R0 ;GET FDB POINTER CMP R0,#P0IN ;IF NOT BEQ 10$ ;STANDARD INPUT CALL $FDBTA ;PUT OUT FILE NAME MOVB #':,(R1)+ ;FOR MOVB #' ,(R1)+ ;LOOKS 10$: MOV (SP)+,R0 ;GET MESSAGE POINTER 20$: MOVB (R0)+,(R1)+ ;COPY BNE 20$ ;THE MESSAGE TEXT MOV #TBUF,R0 ;THEN CALL CCERR ;WRITE TO ERROR STREAM MOV #BUF,R0 ;WRITE THE NULL-TERMINATED LINE, TOO ;19 CALL CCERR ; INC NERRS ;COUNT AN ERROR RETURN ; ;+ ; ** SHARP - OUTPUT A LINE NUMBER RECORD ; ; THIS ROUTINE IS CALLED TO OUTPUT A LINE NUMBER/FILE NAME RECORD ; TO THE OUTPUT FILE. THIS RECORD IS USED TO RESET THE FILENAME ; AND LINE NUMBER IN PASS 1 DIAGNOSTICS. ; ; USES: ; R0, R1 ;- SHARP: MOV #TBUF,R1 ;POINT AT TEMP BUFFER MOVB #'#,(R1)+ ;PUT '#' IN THE BUFFER MOV LINE,R0 ;CONVERT CALL $ITOC ;LINE NUMBER MOV FILE,R0 ;GET FDB POINTER CMP R0,#P0IN ;IF NOT BEQ 10$ ;STANDARD INPUT MOVB #' ,(R1)+ ;OUTPUT CALL $FDBTA ;FILE NAME 10$: SUB #TBUF,R1 ;OUTPUT MOV R1,-(SP) ;PUSH THE BUFFER LENGTH ;04 + MOV #TBUF,-(SP) ;AND THE BUFFER START MOV #P0OUT,R0 ;R0 -> THE FILE DATA BLOCK CALL PUTTXT ;DO IT BIT (SP)+,(SP)+ ;DUMP THE STACK, KEEP C-BIT ;04 - RETURN ;DONE ;+ ; ** PUTBLN - OUTPUT A BLANK LINE ; ; INPUTS: ; NONE ; ; OUTPUTS: ; NONE ; ; USES: ; R0 ;- PUTBLN: ;02 + MOV #1,-(SP) ;PUSH A SHORT RECORD COUNT ;04 + MOV #BLN,-(SP) ;AND THE BLANK RECORD ADDRESS MOV #P0OUT,R0 ;IT GOES TO THIS ONE CALL PUTTXT ;DO IT BIT (SP)+,(SP)+ ;TRASH THE STACK ;04 - RETURN ;LINE NUMBERS ARE CORRECT ;02 - ;+ ; ** EQUAL - COMPARE NAMES ; ; INPUTS: ; R0=POINTER TO 8 BYTE NAME ; IDBUF=ANOTHER 8 BYTE NAME ; ; OUTPUTS: ; C=0 IF THE SAME, C=1 IF DIFFERENT ; ; USES: ; R0, R1 ;- EQUAL: MOV #IDBUF,R1 ;POINT AT ID BUFFER 10$: CMPB (R0)+,(R1)+ ;EQUAL BNE 20$ ;NO CMP R1,#IDBUF+8. ;MAYBE BLO 10$ ;LOOP IF MORE TO COMPARE CLC ;EQUAL BR 30$ ; 20$: SEC ;NOT EQUAL 30$: RETURN ;RETURN .END