CONST INTEGER DIAGOP = 0; ! Non-zero for diagnostic tracing code. CONST INTEGER ULCEQUIV = -1 ! Zero to distinguish upper form lower case in keywords, ! non-zero to treat upper and lower case as equivalent. ! RECORD FORMAT PD (INTEGER BOUND, ADDRESS) ! ! IF ULCEQUIV#0 THEN START SYSTEM ROUTINE SPEC UCTRANSLATE (INTEGER ADDR, LIM) FINISH IF DIAGOP#0 THEN START EXTERNAL ROUTINE LIST PARAMETERS C (INTEGER P, C STRING ARRAY NAME KNAME, C RECORD ARRAY NAME VALUE) RECORD SPEC VALUE (PD) INTEGER I, J, K, L IF P>0 THEN START CYCLE I=1,1,P L = ADDR (KNAME(I)) L = BYTE INTEGER (L) PRINT STRING (KNAME(I)) SPACES (12-LENGTH(KNAME(I))) PRINT SYMBOL ('"') K = VALUE(I)_BOUND & X'00FFFFFF' IF K>0 THEN START L = VALUE(I)_ADDRESS CYCLE J=L,1,L+K-1 PRINT SYMBOL (BYTE INTEGER(J)) REPEAT FINISH PRINT SYMBOL ('"') NEWLINE REPEAT FINISH END FINISH ! SYSTEM ROUTINE ANALYSE PARAMETERS C (STRING NAME DCL PARMS, CALL PARMS, INTEGER MAX PARMS, C STRING ARRAY NAME KEYS, INTEGER MAX KEY SIZE, C RECORD ARRAY NAME ACTUAL, C INTEGER NAME TOTAL KEYS, RESPONSE) ! ! THIS ROUTINE TAKES TWO 'PARAMETER STRINGS', 'DCL PARMS' FROM A ! MACRO DECLARATION AND 'CALL PARM' FROM A CALL OF THE SAME MACRO. ! IT PRODUCES IN THE %STRING %ARRAY 'KEYS' ALL THE KEYWORDS DECLARED IN ! THE MACRO DECLARATION, IN THE CORRECT ORDER, AND IN %RECORD %ARRAY ! 'ACTUAL', BYTE-VECTOR DESCRIPTORS TO THE CORRESPONDING ACTUAL ! PARAMETER TEXTS TO BE USED IN THE CALL. THESE DESCRIPTORS WILL BE ! TO AREAS WITHIN THE %STRING 'CALL PARMS' OR (WHERE A DEFAULT IS ! USED) WITHIN 'DCL PARMS'. A DESCRIPTOR WITH BOUND ZERO WILL ! INDICATE A NULL STRING. ! THE VALUES OF 'MAX PARMS' AND 'MAX KEY SIZE' MUST BE SET ON ENTRY ! TO INDICATE THE MAXIMUM NUMBER OF PARAMETERS AND THE MAXIMUM LENGTH ! OF THE KEYWORD STRINGS WHICH CAN BE ACCEPTED. THE %ARRAYS 'KEYS' ! AND 'ACTUAL' MUST BE DECLARED WITH UPPER BOUNDS NOT LESS THAN ! 'MAX PARMS' AND LOWER BOUNDS OF 1. THE %STRINGS IN %ARRAY 'KEYS' ! MUST HAVE MAXIMUM LENGTH NOT LESS THAN 'MAX KEY SIZE'. ! ON EXIT, 'RESPONSE' WILL BE =0 FOR SUCCESS, >0 FOR WARNINGS AND ! <0 FOR FAILURE. AS WELL AS THE SIGN BIT, OTHER BITS MAY BE SET ! TO INDICATE SPECIFIC WARNING OR ERROR CONDITIONS. ! BIT 24 (VALUE 128)- KEYWORDS INDISTINCT: TWO KEYWORDS HAVE THE ! SAME FIRST CHARACTERS, SO THAT THEIR ! ABBREVIATIONS COULD NOT BE DISTINGUISHED ! IN A CALL. ! BIT 25 (VALUE 64) - 'WRAP-AROUND': FIRST CHARACTER HAS BEEN ! SPECIFIED BY POSITION, BUT NOT IN FIRST ! POSITION IN THE CALL. ! BIT 26 (VALUE 32) - SOME PARAMETER SPECIFIED MORE THAN ONCE: ! LATEST VALUE ACCEPTED. ! BIT 27 (VALUE 16) - UNRECOGNISED KEYWORD IN CALL: FIELD IGNORED. ! BIT 28 (VALUE 8) - KEYWORD TOO LONG IN CALL: ! EXTRA CHARACTERS IGNORED. ! BIT 29 (VALUE 4) - TOO MANY FIELDS IN DECLARATION. ! BIT 30 (VALUE 2) - KEYWORD TOO LONG IN DECLARATION: ! EXTRA CHARACTERS IGNORED. ! BIT 31 (VALUE 1) - FIELD WITH NO KEYWORD IN DECLARATION. ! ! IF 'RESPONSE'>=0, THEN 'TOTAL KEYS' WILL ALSO BE SET TO INDICATE HOW ! MANY PARAMETERS THERE ARE. ! ! ROUTINE PICK UNIT (INTEGER NAME CHAD, CHEND, C INTEGER DECL, STRING NAME KEYWORD, INTEGER KSIZE, C INTEGER NAME VLIM, VADDR, INTEGER NAME R) ! THIS ROUTINE SCANS BYTES FROM ADDRESS CHAD+1 TO ! ADDRESS CHEND (INCREMENTING CHAD AS IT GOES), TO FIND ! A KEYWORD AND/OR A PARAMETER VALUE. IT COPIES THE KEYWORD ! INTO THE PARAMETER 'KEYWORD', AND PUTS THE LENGTH AND ! ADDRESS OF THE PARAMETER VALUE INTO VLIM AND VADDR ! RESPECTIVELY. ! VADDR WILL BE BETWEEN (INITIAL VALUE OF) CHAD + 1 AND ! THE FINAL VALUE OF CHAD - 1. VLIM+VADDR-1 WILL ALSO LIE ! IN THAT RANGE. VLIM WILL NOT BE LESS THAN ZERO. ! ON ENTRY, CHAD MUST HAVE (ADDRESS OF THE FIRST CHARACTER ! TO BE EXAMINED) - 1. CHEND MUST HAVE THE ADDRESS OF THE ! LAST CHARACTER TO BE EXAMINED. ON EXIT, CHAD WILL HAVE BEEN ! UPDATED TO POINT TO THE LAST CHARACTER EXAMINED. IF IT ! IS THEN GREATER THAN CHEND, THE ORIGINAL TEXT HAS BEEN ! EXHAUSTED. IF IT IS EQUAL TO CHEND, THEN THE LAST CHARACTER ! OF THE ORIGINAL TEXT WAS THE COMMA WHICH TERMINATED THE ! PARAMETER FIELD. IF CHAD IS GREATER THAN OR EQUAL TO CHEND ON ! ENTRY, THEN THE ROUTINE WILL RETURN IMMEDIATELY WITH CHAD ! UNALTERED, WITH A NULL STRING IN KEYWORD, AND WITH VLIM=0. ! THERE WILL BE NO ERROR INDICATION IN THIS CASE. ! IF NO KEYWORD IS DETECTED IN A CALL ON PICK UNIT, THEN ! KEYWORD WILL BE ASSIGNED A NULL STRING. IF NO PARAMETER ! VALUE IS DETECTED, OR IF THE VALUE IS A NULL STRING, THEN ! VLIM WILL BE ZERO. WHERE A FIELD CONTAINS NO "=" SYMBOL ! (AND WHEN THERE IS NO OTHER WAY OF RESOLVING THE AMBIGUITY), ! THE VALUE OF THE PARAMETER DECL DECIDES WHETHER ANY TEXT ! FOUND IS TO BE TAKEN TO BE A KEYWORD (APPROPRIATE IN ! ANALYSING MACRO DECLARATIONS: DECL NON-ZERO) OR A ! PARAMETER VALUE (APPROPRIATE IN ANALYSING A CALL: DECL ZERO). ! THE PARAMETER KSIZE SPECIFIES THE MAXIMUM PERMISSIBLE SIZE OF ! THE STRING KEYWORD. ! ERRORS ARE NOTIFIED BY THE VALUE OF R ON EXIT. A ZERO VALUE ! MEANS THAT NO ERRORS HAVE OCCURRED. THE ONLY ERROR CONDITION ! DEFINED SO FAR IS "KEYWORD TOO LONG", GIVING R=1. INTEGER TS, KADDR, KLIM, CHIN, CHYPE, BL, PAST ! ! THE ARRAY 'PROCN' IS INDEXED BY 'CHYPE' AND 'PAST' TO SELECT A ! DESTINATION IN THE SWITCH 'PROCN'. THIS PASSES CONTROL TO A ! PROCESS APPROPRIATE TO THE PRESENT STATE OF THE ANALYSIS ('PAST') ! AND THE CHARACTER BEING INSPECTED IN THE PARAMETER STRING ('CHYPE'). ! VALUES OF 'CHYPE' ARE: ! 0 - NO TEXT LEFT TO EXAMINE; ! 1 - LETTER; ! 2 - DIGIT; ! 3 - SPACE; ! 4 - COMMA; ! 5 - 'EQUALS' SIGN; ! 6 - OPEN BRACKET; ! 7 - CLOSE BRACKET; ! 8 - DOUBLE-QUOTE; ! 9 - ANYTHING ELSE. ! VALUES OF 'PAST' ARE: ! 1 - STARTING: NO NON-SPACE CHARACTER SEEN YET. ! 2 - TEXT FOUND, BUT STILL UNDECIDED WHETHER IT IS KEYWORD OR VALUE. ! 3 - PROCESSING THE 'VALUE' PART OF THE PARAMETER FIELD. ! 4 - IN QUOTES (AND THIS CAN ONLY BE IN THE VALUE PART). CONST BYTE INTEGER ARRAY PROCN (0:9,1:4) = C 16, 10, 8, 0, 16, 8, 9, 8, 7, 8, 15, 11, 11, 2, 15, 4, 9, 8, 7, 8, 14, 1, 1, 3, 14, 1, 12, 13, 6, 1, 17, 1, 1, 2, 1, 1, 1, 1, 5, 1 ! %STRING (1) CHST ! %STRING (5) DISCARD ! %CONST %STRING (6) SPC = " ,=()""" SWITCH PERFORM (0:17) ! LENGTH (CHST) = 1 R = 0 KADDR = ADDR (KEYWORD) KLIM = 0 VADDR = CHAD + 1 VLIM = 0 BL = 0 PAST = 1 TS = 0 -> SEECH ! ! PERFORM(10): PAST = 2 PERFORM(11): IF KLIM>=KSIZE C THEN R = R ! 1 C ELSE START KLIM = KLIM + 1 BYTE INTEGER (KADDR+KLIM) = CHIN FINISH PERFORM(1): ADD NS: TS = 0 ADD TO F: VLIM = VLIM + 1 ! SEECH: CHAD = CHAD + 1 IF CHAD>CHEND THEN -> PERFORM (PROCN(0,PAST)) CHIN = BYTE INTEGER (CHAD) ! ! **** **** THIS NEXT SECTION IS A CANDIDATE **** **** ! **** **** FOR MACHINE CODING, BUT FOR THE **** **** ! **** **** MOMENT I HAVE USED A BIT OF **** **** ! **** **** TRICKERY WITH %STRINGS SPC, CHST **** **** ! **** **** AND DISCARD. THEIR DECLARATIONS **** **** ! **** **** WILL NOT BE NEEDED IF THIS BIT **** **** ! **** **** OF CODE IS REPLACED. **** **** ! **** **** IN FACT MY NEW CODE ACTUALLY **** **** ! **** **** TAKES MORE SPACE THAN THE OLD, **** **** ! **** **** SO I HAVE COMMENTED IT OUT, BUT **** **** ! **** **** I HAVE LEFT THE TEXT HERE AS AN **** **** ! **** **** INDICATION OF THE SORT OF CODE **** **** ! **** **** I HAD IN MIND. **** **** IF 'A'<=CHIN<='Z' C OR (ULCEQUIV#0 AND 'a'<=CHIN<='z') C THEN CHYPE = 1 ELSE START IF '0'<=CHIN<='9' THEN CHYPE = 2 ELSE START IF CHIN=' ' THEN CHYPE = 3 ELSE START IF CHIN=',' THEN CHYPE = 4 ELSE START IF CHIN='=' THEN CHYPE = 5 ELSE START IF CHIN='(' THEN CHYPE = 6 ELSE START IF CHIN=')' THEN CHYPE = 7 ELSE START IF CHIN='"' THEN CHYPE = 8 ELSE CHYPE = 9 FINISH FINISH FINISH FINISH FINISH ! EQUIVALENT TO THAT, AND (I HOPE) FASTER AND MORE COMPACT: ! BUT IN FACT IT TAKES MORE SPACE, AND I HAVE NOT CHECKED ITS ! SPEED! ! BYTE INTEGER (ADDR(CHST)+1) = CHIN ! %IF SPC->DISCARD.(CHST) %C ! %THEN CHYPE = LENGTH(RESIDUE) + 3 %C ! %ELSE CHYPE = 9 FINISH FINISH ! **** **** END OF MACHINE CODE SECTION **** **** ! -> PERFORM (PROCN(CHYPE,PAST)) ! PERFORM(9): BL = 1 PERFORM(8): KLIM = 0 PERFORM(5): PAST = 3 -> ADD NS ! PERFORM(7): KLIM = 0 PERFORM(6): PAST = 4 -> ADD NS ! PERFORM(4): VADDR = CHAD + 1 VLIM = 0 TS = 0 PAST = 3 -> SEECH ! PERFORM(3): IF VLIM#0 THEN -> ADD S PERFORM(0): VADDR = VADDR + 1 -> SEECH PERFORM(2): ADD S: TS = TS + 1 -> ADD TO F ! PERFORM(12): BL = BL + 1 -> ADD NS ! PERFORM(13): IF BL>0 THEN BL = BL - 1 -> ADD NS ! PERFORM(14): IF BL>0 THEN -> ADD NS -> UNIT COMPLETE ! PERFORM(15): IF DECL=0 THEN KLIM = 0 ELSE TS = VLIM PERFORM(17): UNIT COMPLETE: VLIM = VLIM - TS PERFORM(16): LENGTH (KEYWORD) = KLIM IF ULCEQUIV=0 THEN START IF KLIM=0 THEN R = R & X'FFFFFFFE' FINISH ELSE START IF KLIM=0 THEN R = R & X'FFFFFFFE' ELSE UCTRANSLATE (KADDR+1,KLIM) FINISH RETURN END ! ! INTEGER CPTR, CLIM, RESULT, VS, VP, L, M, KM, KN, CSTART INTEGER WRAPPING, KEY VALID INTEGER NAME VALSIZE, VALPTR RECORD NAME VAL (PD) STRING (255) CALL KEY, RESIDUE STRING NAME THIS KEY, THAT KEY ! RESPONSE = 0 CPTR = ADDR (DCL PARMS) CLIM = CPTR + LENGTH (DCL PARMS) IF CLIM=CPTR THEN START TOTAL KEYS = 0 RETURN FINISH KN = 0 WHILE CPTR<CLIM AND KN<MAX PARMS CYCLE KN = KN + 1 THIS KEY == KEYS (KN) VAL == ACTUAL (KN) VALSIZE == VAL_BOUND VALPTR == VAL_ADDRESS PICK UNIT (CPTR,CLIM,-1,THIS KEY,MAX KEY SIZE,VALSIZE,VALPTR,RESULT) VALSIZE = VALSIZE ! X'18000000' L = LENGTH (THIS KEY) IF L=0 THEN START RESPONSE = RESPONSE ! X'80000001' CPTR = CLIM + 1 FINISH ELSE START IF RESULT#0 THEN RESPONSE = RESPONSE ! 2 KM = 1 IF L>3 THEN L=3 WHILE KM<KN CYCLE THAT KEY == KEYS (KM) M = LENGTH (THAT KEY) IF M>L THEN M=L ! ! **** **** MACHINE CODE HERE? **** **** IF FROM STRING(THIS KEY,1,M)=FROM STRING(THAT KEY,1,M) C THEN RESPONSE = RESPONSE ! X'80000080' ! **** **** END OF MACHINE CODE **** **** ! KM = KM + 1 REPEAT FINISH REPEAT IF CPTR<=CLIM THEN RESPONSE = RESPONSE ! X'80000004' IF RESPONSE<0 THEN RETURN TOTAL KEYS = KN KN = 1 WRAPPING = 0 CSTART = ADDR (CALL PARMS) CPTR = CSTART CLIM = CPTR + LENGTH (CALL PARMS) WHILE CPTR<CLIM CYCLE PICK UNIT (CPTR,CLIM,0,CALL KEY,MAX KEY SIZE,VS,VP,RESULT) IF RESULT#0 THEN RESPONSE = RESPONSE ! 8 KEY VALID = 0 IF LENGTH(CALL KEY)>0 THEN START KN = 0 IF LENGTH(CALL KEY)<3 THEN START UNTIL KN>TOTAL KEYS OR KEYS(KN)=CALL KEY CYCLE KN = KN + 1 REPEAT FINISH ELSE START UNTIL KN>TOTAL KEYS C OR KEYS(KN)->(CALL KEY).RESIDUE C CYCLE KN = KN + 1 REPEAT FINISH IF KN>TOTAL KEYS THEN START RESPONSE = RESPONSE ! X'00000010'; ! UNRECOGNISED KEYWORD. FINISH ELSE START KEY VALID = -1 FINISH FINISH ELSE START IF VS#0 THEN START IF KN=1 AND WRAPPING#0 C THEN RESPONSE = RESPONSE ! X'00000040' KEY VALID = -1 FINISH FINISH IF KEY VALID#0 THEN START VAL == ACTUAL (KN) IF CSTART<=VAL_ADDRESS<CLIM C THEN RESPONSE = RESPONSE ! X'00000020' VAL_BOUND = VS ! X'18000000' VAL_ADDRESS = VP FINISH KN = KN + 1 IF KN>TOTAL KEYS THEN START KN = 1 WRAPPING = -1 FINISH REPEAT RETURN ! ! END ! ! END OF FILE