.TITLE CC001 .IDENT /X01/ .NLIST BEX .ENABL LC ; ; C COMPILER ; PREPROCESSOR ; ; VERSION X01 ; ; DAVID G. CONROY 17-JAN-78 ; .GLOBL CCPREP .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$ ; ; 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 ; 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 AFDB ;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 IDBUF: .BLKB 8. ;ID BUFFER TBUF: .BLKB 128. ;TEMP. BUFFER BUF: .BLKB 128. ;RECORD BUFFER DEF: .BYTE 144,145,146,151 ;DEFINE IN .BYTE 156,145,000,000 ;LOWER CASE INC: .BYTE 151,156,143,154 ;INCLUDE IN .BYTE 165,144,145,000 ;LOWER CASE BLN: .ASCII " " ;FOR OUTPUT OF A BLANK LINE SYSINC: .ASCIZ "LB:[1,1]" ;SYSTEM INCLUDE DIRECTORY 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" .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 SFDB, AND THE ORIGINAL USER ; SOURCE OPEN FOR READING ON AFDB (AFDB WILL EVENTUALLY BE REUSED AS ; THE ASM OUTPUT FDB). ; ; THIS ROUTINE READS THE SOURCE, PERFORMING THE REQUIRED DEFINES AND ; INCLUDES, AND WRITING THE WHOLE LOT TO THE TEMP FILE. ;- CCPREP: GET$S FILE,#BUF,#128. ;READ A SOURCE LINE BCS 30$ ;ERROR, MIGHT BE EOF INC LINE ;UPDATE LINE NUMBER MOV #BUF,BEND ;COMPUTE THE ADDRESS OF THE ADD F.NRBD(R0),BEND ;END OF THE RECORD 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 CCPREP ;AND GO FOR MORE 20$: CALL EXPAND ;EXPAND ANY MACROS MOV BEND,R1 ;COMPUTE RECORD SUB #BUF,R1 ;SIZE PUT$S #SFDB,#BUF,R1 ;WRITE IT OUT BCC CCPREP ;AND GO FOR MORE MOV #ERR01,R0 ;I/O ERROR ON OUTPUT JMP CCABRT ;DIE 30$: CMPB F.ERR(R0),#IE.EOF ;IS THE ERROR END OF FILE BEQ 40$ ;YES MOV #ERR02,R0 ;I/O ERROR ON INPUT JMP CCABRT ;DIE 40$: CMP FILE,#AFDB ;IS THE FILE STANDARD INPUT BEQ 50$ ;YES CLOSE$ FILE ;NO, CLOSE THE INCLUDE FILE MOV #AFDB,FILE ;SET FILE TO STANDARD INPUT MOV STLINE,LINE ;BACK UP LINE NUMBER CALL SHARP ;OUTPUT A SHARP RECORD AND BR CCPREP ;GO BACK FOR MORE 50$: RETURN ;DONE ;+ ; ** 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 65$ ;IGNORE BLANK LINES CALL GETID ;GET TYPE MOV #DEF,R0 ;TEST FOR CALL EQUAL ;DEFINE BCS 70$ ;BR IF NOT 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 BCS 30$ ;NOT THERE 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 IOT ;MUST BE THERE 20$: MOV (R0),(R1) ;UNLINK THE ITEM IN QUESTION CALL $FREE ;FREE IT 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 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 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 ERROR ;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$: PUT$S #SFDB,#BLN,#1 ;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 100$ ;BR IF NOT CMP FILE,#AFDB ;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 LB:[1,1] 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$: 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 #IFDB,R0 ;OPEN MOV #IFDB+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 MOV LINE,STLINE ;SAVE LINE NUMBER CLR LINE ;RESET LINE NUMBER MOV #IFDB,FILE ;RESET FILE NAME CALL SHARP ;OUPUT '#' RECORD BR 130$ ;DONE 100$: MOV #ERR05,R0 ;ILLEGAL CONTROL LINE BR 120$ ; 110$: MOV #ERR06,R0 ;CONNOT OPEN FILE 120$: CALL ERROR ;COMPLAIN 130$: RETURN ;FINIS ;+ ; ** 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 ; BEND=POINTER TO THE END OF THE RECORD ;- EXPAND: MOV #BUF,R5 ;POINT AT THE START 10$: CMP R5,BEND ;BREAK LOOP IF BLO 12$ ;ALL JMP 170$ ;DONE 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 10$ ;YES 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 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 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 10$ ;NO 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 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 BR 140$ ;GO COPY IN TEXT 110$: ADD BEND,R4 ;NEW LINE IS LONGER CMP R4,#BUF+128. ;IS THE LINE TOO LONG BLO 120$ ;NO MOV #ERR03,R0 ;COMPLAIN CALL ERROR ;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 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 10$ CMPB R0,#'9 BLOS 20$ OKSID: 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 ;- 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$: 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 ;+ ; ** ERROR - OUT OUT ERROR MESSAGES ; ; INPUTS: ; R0=POINTER TO ASCIZ MESSAGE ; ; USES: ; R0, R1 ;- ERROR: 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,#AFDB ;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 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,#AFDB ;IF NOT BEQ 10$ ;STANDARD INPUT MOVB #' ,(R1)+ ;OUTPUT CALL $FDBTA ;FILE NAME 10$: SUB #TBUF,R1 ;OUTPUT PUT$S #SFDB,#TBUF,R1 ;THE RECORD RETURN ;DONE ;+ ; ** 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