CONST  INTEGER  DIAGOP = 0; ! No diagnostic trace requested.
CONST  INTEGER  ULCEQUIV = -1
! Zero to make macro expansion distinguish upper and lower case in keywords,
! non-zero to make it treat upper and lower case as equivalent.
!
INCLUDE  "SS0302S_SSOWNF"
!
RECORDFORMAT  RF(INTEGER  CONAD, FILETYPE, DATASTART, DATAEND)
! %RECORD %FORMAT PD (%INTEGER BOUND, ADDRESS)
! %RECORD %FORMAT SD (%INTEGER BOUND, ADDRESS, CURRENT OFFSET, CLASS, %C
!     %INTEGER PARM COUNT, %STRING %ARRAY %NAME KWDN, %C
!     %RECORD(PD) %ARRAY %NAME PARM VAL DET)
IF  ULCEQUIV#0 THEN  START 
   SYSTEM  ROUTINE  SPEC  UCTRANSLATE (INTEGER  A, L)
FINISH 
SYSTEM  ROUTINE  SPEC  MOVE (INTEGER  LENGTH, FROM, TO)
SYSTEM  INTEGER  FN  SPEC  JOB READ CH
SYSTEM  INTEGER  FN  SPEC  JOB NEXT CH
SYSTEMROUTINESPEC  CONNECT(STRING  (31) FILE,  C 
   INTEGER  MODE, HOLE, PROT, RECORD (RF)NAME  R, INTEGERNAME  FLAG)
SYSTEM  ROUTINE  SPEC  OUTFILE (STRING  (31) NAME, C 
    INTEGER  BYTES, HOLE, PROT, INTEGER  NAME  CONAD, FLAG)
!
IF  DIAGOP#0 THEN  START 
   EXTERNAL  ROUTINE  SPEC  LIST PARAMETERS C 
       (INTEGER  P, C 
        STRING  ARRAY  NAME  KNAME, C 
        RECORD (PD) ARRAY  NAME  VALUE)
FINISH 
!
! THE CLASS WORD IN THESE RECORDS IS LAID OUT AS FOLLOWS:
! BITS 4 TO 31: 1 FOR "DIRECT INPUT VIA READ CH",
!               2 FOR "DIRECT INPUT FROM AN AREA OF STORE",
!               3 FOR "INPUT THROUGH THE MACRO EXPANSION
!                 PROCESS FROM AN AREA OF STORE".
! BIT 0: (ONLY RELEVANT FOR CLASSES 2 AND 3, I.E., INPUT FROM AN
!        AREA OF STORE, WITH OR WITHOUT MACRO EXPANSION): IF THIS
!        BIT IS ZERO, THEN WHEN THE AREA IS EXHAUSTED, THE USER
!        WILL GET NO NOTIFICATION FROM 'MASTER CHAR IN', AND INPUT
!        WILL AUTOMATICALLY RESUME FROM WHERE IT LEFT OFF IN THE
!        PREVIOUS LEVEL.  IF THIS BIT IS NON-ZERO, THEN THE USER WILL
!        BE GIVEN THE CHARACTER 25(DECIMAL), AND INPUT WILL NOT BE
!        SWITCHED TO THE PREVIOUS LEVEL UNTIL THE USER CALLS 'ABANDON
!        LEVEL'.
! BIT 3: ONLY RELEVANT FOR CLASS 2 (INPUT FROM AN AREA OF STORE WITHOUT
!        MACRO EXPANSION) WITH BIT 0 NON-ZERO (REQUESTING EXPLICIT
!        NOTIFICATION OF END-OF-AREA).  IF THIS BIT IS ZERO, NO SPECIAL
!        ACTION WILL BE TAKEN.  IF IT IS NON-ZERO, THEN THE LAST
!        CHARACTER IS GUARANTEED TO BE A NEWLINE.  THAT IS,
!        'MASTER CHAR IN' WILL SUPPLY A NEWLINE BEFORE THE '25'
!        CHARACTER, IF THERE IS NOT A NEWLINE IN THE LAST
!        POSITION IN THE AREA.  THIS PROVISION WILL NOT APPLY
!        IF THE AREA IS EMPTY (I.E., OF LENGTH ZERO).
! BIT 2: RELEVANT FOR CLASSES 2 AND 3 (INPUT FROM AREAS OF STORE
!        WITH OR WITHOUT MACRO EXPANSION).  IF THIS IS NON-ZERO,
!        THE AREA IS ASSUMED TO BE 'FIXED IN STORE'.  THIS MEANS THAT,
!        IN PASSING OUT A BYTE FROM THE AREA, 'MASTER CHAR IN' SHOULD
!        SET 'IN CHAR ADDR' TO POINT TO THE BYTE.  ANYONE WANTING
!        TO 'REMEMBER' PARTS OF THE TEXT NEED ONLY KEEP POINTERS,
!        AND NEED NOT COPY THE TEXT, SINCE IT SHOULD REMAIN IN
!        THE SAME PLACE FOR THE DURATION OF THE 'JOB' OR 'SESSION'.
!        IF THIS IS NOT TRUE - I.E., IF THE TEXT IS 'VOLATILE' (FOR
!        INSTANCE, PARAMETER VALUES FOR MACROS) - THEN BIT 2 OF THE
!        'CLASS' WORD SHOULD BE ZERO.
! BIT 1: ONLY RELEVANT FOR CLASS 3 (MACRO EXPANSION).  WHEN THE MACRO
!        TEXT IS EXHAUSTED, THE 'BRACKET OPTION' WILL BE SET 'ON' IF
!        THIS BIT IS NON-ZERO, AND 'OFF' IF IT IS ZERO.  THAT IS, THIS
!        BIT IS USED TO SAVE THE APPROPRIATE OPTION BEFORE IT IS
!        ADJUSTED TO SUIT THE TEXT WITHIN THE MACRO, AND THE OPTION WILL
!        REVERT PROPERLY ON 'EXIT' FROM THE MACRO.
!
! %OWN %INTEGER WSP BASE = 0, WSP LIM, WSP PTR
! %EXTERNAL %INTEGER IN SOURCE = 0
! %CONST %INTEGER SOURCE LEVELS = 15
! %OWN %RECORD(SD) %ARRAY SOURCE DETAIL (0:SOURCE LEVELS+1)
! ALLOW ONE EXTRA LEVEL FOR PARAMETER SUBSTITUTION IN A MACRO CALL
! BECAUSE IT ISN'T PRACTICAL TO CHECK THE LEVELS AT
! THE MOMENT OF MAKING THE SUBSTITUTION.  ONE EXTRA LEVEL
! WILL ALWAYS BE SUFFICIENT.
! %OWN %INTEGER SCADDR, SHORT CUT = 0
CONST  STRING  (2) EXPANDER = "%%"
! %EXTRINSIC %INTEGER BRACKET FLAG
!
!
! THE VARIABLE 'IN CHAR ADDR' IS SET BY EVERY CALL OF 'MASTER CHAR IN'
! TO GIVE THE ADDRESS OF THE CHARACTER RETURNED.  IF THE CHARACTER IS
! 'VOLATILE' - I.E., NOT CERTAIN TO CONTINUE TO EXIST AT ONE ADDRESS -
! THEN 'IN CHAR ADDR' WILL BE SET TO ZERO.  THIS APPLIES TYPICALLY TO
! CHARACTERS READ FROM A CONSOLE, OR CHARACTERS GENERATED BY PARAMETER
! SUBSTITUTION IN A MACRO.
! %EXTERNAL %INTEGER IN CHAR ADDR
! %EXTERNAL %INTEGER LAST CHAR READ
!
!
! %EXTERNAL %INTEGER KWD MAX SIZE
CONST  INTEGER  KWD MAX = 11
! THIS IS THE MAXIMUM LENGTH ALLOWED FOR KEYWORD STRINGS.
! 'START MACROUTINES' COPIES IT INTO 'KWD MAX SIZE', SO THAT
! OTHER ROUTINES CAN CHECK IT.  THE STRINGS IN 'KEY ARRAY DV'
! MUST BE OF THIS LENGTH.
! %OWN %STRING (11) %ARRAY %FORMAT KEY ARRAY DV (1:1000)
! %OWN %RECORD(PD) %ARRAY %FORMAT VAL DESC DV (1:1000)
CONST  STRING  (11) ARRAY  FORMAT  KEY ARRAY DV (1:1000)
CONST  RECORD (PD) ARRAY  FORMAT  VAL DESC DV (1:1000)
! %EXTERNAL %INTEGER MAC INITIALISED = 0
!
SYSTEM  ROUTINE  NEW LEVEL C 
    (INTEGER  BOUND, ADDRESS, EOFACT, INTEGER  NAME  R)
! 'ADDRESS' MUST HAVE THE ADDRESS OF THE FIRST BYTE OF AN AREA OF STORE.
! 'BOUND' MUST HAVE, IN ITS THREE LESS SIGNIFICANT BYTES, THE LENGTH OF
! THE AREA IN BYTES.  THE VALUE OF THE MOST SIGNIFICANT BYTE OF 'BOUND'
! IS IMMATERIAL.
! THIS ROUTINE WILL SET UP THE AREA FOR INPUT VIA 'MASTER CHAR IN'.
! INPUT WILL BE BY DIRECT READING, NOT THROUGH THE MACRO EXPANSION
! PROCESS.  IF THE AREA REPRESENTS A MACRO, DIRECT READING IS
! APPROPRIATE FOR PROCESSING THE MACRO HEADER, AND AFTER THE PARAMETER
! VALUES HAVE BEEN ESTABLISHED, A CALL OF 'USE AS MACRO' WILL MAKE THE
! NECESSARY ADJUSTMENTS TO ALLOW THE REST OF THE AREA TO BE READ VIA
! THE MACRO EXPANSION PROCESS.
! THE PARAMETER 'EOFACT' DETERMINES HOW END-OF-AREA WILL BE TREATED.
! IF EOFACT#0, THEN ANY ATTEMPT TO READ BEYOND THE END OF THE AREA WILL
! RETURN THE VALUE 25 (DECIMAL).  IF EOFACT=0, THEN THE CALLER WILL
! RECEIVE NO INDICATION THAT END-OF-AREA HAS BEEN REACHED, AND INPUT
! WILL RESUME AT THE POINT IT HAD REACHED BEFORE 'NEW LEVEL' WAS CALLED.
! THUS EOFACT=0 WOULD BE APPROPRIATE IF THE NEW LEVEL REPRESENTS, FOR
! INSTANCE, A PARAMETER VALUE TO BE SUBSTITUTED IN EXPANDING A MACRO.
! EOFACT#0 WOULD BE SUITABLE IF THE AREA IS A FILE TO BE READ BY A USER
! PROGRAM.  IF EOFACT=1, A SPECIAL PROVISION OPERATES WHEREBY, IF THE
! NEW LEVEL CONTAINS ANY TEXT AT ALL, THE LAST CHARACTER OF THE LEVEL IS
! GUARANTEED TO BE A NEWLINE.  IF A NEWLINE IS NOT PRESENT IN THE TEXT,
! ONE WILL BE SUPPLIED BY 'MASTER CHAR IN' BEFORE THE CHARACTER 25.
! THE RESULT R=0 INDICATES SUCCESS, AND R#0 INDICATES FAILURE.  THE ONLY
! FAILURE CONDITION IS 'TOO MANY INPUT LEVELS', GIVING R=X'80001000'.
RECORD (SD) NAME  CURRENT IN DETAILS
IF  SSOWN_IN SOURCE<SOURCE LEVELS THEN  START 
    IF  SSOWN_SHORT CUT#0 THEN  START 
        CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_IN SOURCE)
        CURRENT IN DETAILS_CURRENT OFFSET = C 
            SSOWN_SCADDR - CURRENT IN DETAILS_ADDRESS
        SSOWN_SHORT CUT = 0
    FINISH 
    SSOWN_IN SOURCE = SSOWN_IN SOURCE + 1
    CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_IN SOURCE)
    CURRENT IN DETAILS_BOUND = BOUND
    CURRENT IN DETAILS_ADDRESS = ADDRESS
    CURRENT IN DETAILS_CURRENT OFFSET = 0
    IF  EOFACT#0 THEN  START 
        IF  EOFACT=1 C 
        THEN  EOFACT = X'90000000' C 
        ELSE  EOFACT = X'80000000'
    FINISH 
    CURRENT IN DETAILS_CLASS = EOFACT ! X'20000002'
    R = 0
FINISH  ELSE  R = X'80001000'
END 
!!
EXTERNAL  ROUTINE  RESET JCL (STRING  (255) DUMMY)
   SSOWN_MAC INITIALISED = 0
END 
!
SYSTEM  ROUTINE  START MACROUTINES C 
    (INTEGER  BOUND, ADDRESS, INTEGER  NAME  R)
INTEGER  CONFLAG
RECORD (RF) RR
! THIS ROUTINE MUST BE CALLED EXACTLY ONCE BEFORE ANY OF THE OTHERS
! IN THIS SUITE.  IT DEFINES THE PRIMARY INPUT STREAM FOR COMMANDS.
! IF THE INPUT STREAM IS TO BE AN AREA OF VIRTUAL STORE (E.G., A FILE
! OR PART OF A FILE, OR A STRING), THEN 'BOUND' MUST HAVE THE SIZE OF
! THE AREA IN BYTES, AND 'ADDRESS' MUST HAVE THE ADDRESS OF THE FIRST
! BYTE OF THE AREA.  IF THE INPUT STREAM IS TO BE FROM A TERMINAL, THEN
! 'BOUND' MUST BE ZERO AND THE VALUE OF 'ADDRESS' IS IMMATERIAL.  IN
! EITHER CASE, 'BOUND' IS ALWAYS TREATED AS IF ITS MOST SIGNIFICANT
! BYTE WERE ZERO, REGARDLESS OF ITS ACTUAL VALUE.  THIS ALLOWS THE
! BOUND WORD OF A DESCRIPTOR TO BE USED.
R = 0
IF  SSOWN_MAC INITIALISED#0 THEN  START 
    IF  ADDRESS#0 THEN  NEW LEVEL (BOUND,ADDRESS,1,R)
FINISH  ELSE  START 
    SSOWN_KWD MAX SIZE = KWD MAX
    SSOWN_LAST CHAR READ = NL
    IF  SSOWN_WSP BASE=0 THEN  START 
        SSOWN_WSP LIM = 8192
        CONNECT("T#MACSTACK",3,0,0,RR,CONFLAG)
        IF  CONFLAG = 0 START 
           SSOWN_WSP BASE = RR_CONAD
        ELSE 
           OUTFILE ("T#MACSTACK",SSOWN_WSP LIM,0,8,SSOWN_WSP BASE,CONFLAG)
        FINISH 
        SSOWN_WSP LIM = SSOWN_WSP BASE + SSOWN_WSP LIM
        SSOWN_WSP PTR = SSOWN_WSP BASE
    FINISH 
    SSOWN_IN SOURCE = 0
    SSOWN_SOURCE DETAIL(0)_CURRENT OFFSET = 0
    IF  BOUND&X'00FFFFFF'=0 THEN  START 
        SSOWN_SOURCE DETAIL(0)_CLASS = X'90000001'
    FINISH  ELSE  START 
        SSOWN_SOURCE DETAIL(0)_CLASS = X'B0000002'
        SSOWN_SOURCE DETAIL(0)_BOUND = BOUND
        SSOWN_SOURCE DETAIL(0)_ADDRESS = ADDRESS
    FINISH 
    SSOWN_MAC INITIALISED = -1
FINISH 
SSOWN_SHORT CUT = 0
END 
!
!
SYSTEM  ROUTINE  MACOPEN
!
! THIS IS A CUT-DOWN VERSION OF 'START MACROUTINES' TO BE USED
! WHEN THE MACRO ROUTINES ARE ONLY TO BE USED FOR EXAMINING THE
! HEADER LINE OF A MACRO.
!
IF  SSOWN_MAC INITIALISED=0 THEN  START 
    SSOWN_WSP LIM = 0
    SSOWN_WSP PTR = 0
    SSOWN_WSP BASE = 0
    SSOWN_IN SOURCE = 0
    SSOWN_SOURCE DETAIL(0)_CLASS = X'B0000002'
    SSOWN_SOURCE DETAIL(0)_BOUND = 0
    SSOWN_SOURCE DETAIL(0)_ADDRESS = 0
    SSOWN_SOURCE DETAIL(0)_CURRENT OFFSET = 0
    SSOWN_SHORT CUT = 0
FINISH 
END 
!
!
SYSTEM  ROUTINE  USE AS MACRO (INTEGER  NPARM, C 
    STRING  ARRAY  NAME  KEYWORDS, C 
    RECORD (PD) ARRAY  NAME  ACTUAL PARMS, C 
    INTEGER  BFLAG, INTEGER  NAME  FAILURE)
! IF AN AREA HAS BEEN SET UP FOR 'DIRECT INPUT' (BY 'NEW LEVEL'), THEN
! THIS ROUTINE WILL ADJUST THE TABLES SO THAT THE REMAINDER OF THE AREA
! - I.E., ANY WHICH HAS NOT YET BEEN READ - WILL BE READ VIA THE MACRO
! EXPANSION PROCEDURE.  ON "EXIT" FROM THE MACRO, INPUT WILL REVERT
! TO THE NEXT OUTER LEVEL WITHOUT ANY NOTIFICATION TO THE USER OF
! 'MASTER CHAR IN'.  WHEN INPUT REVERTS, THE "BRACKETS" OPTION WILL BE
! SET ACCORDING TO THE VALUE OF 'BFLAG' SUPLIED IN THE CALL ON
! 'USE AS MACRO'.  THUS WHEN YOU CALL 'USE AS MACRO', YOU SHOULD PASS IN
! YOUR CURRENT VALUE OF THE "BRACKET" FLAG, AND AFTER THAT YOU MAY
! CHANGE THE FLAG TO SUIT THE TEXT INSIDE THE MACRO.
! THE ONLY ERROR CONDITION REPORTED BY THIS ROUTINE IS
! 'TOO LITTLE SPACE IN THE MACRO WORK AREA', WHICH GIVES
! FAILURE = X'80000400'.  OTHERWISE FAILURE WILL BE ZERO ON EXIT.
!
INTEGER  I, J, OLD PTR
! %INTEGER K, M; ! **** NOT NEEDED IF WE USE 'MOVE' ****
INTEGER  KTLIM, MOVE SIZE, MOVE DEST; ! **** NEEDED ****
    ! **** ONLY IF WE ARE USING 'MOVE' - SEE BELOW. ****
RECORD (PD) NAME  COPY SOURCE DR
RECORD (PD) ARRAY  NAME  PV COPY
RECORD (SD) NAME  CURRENT IN DETAILS
INTEGER  NAME  OFFSET
FAILURE = 0
IF  BFLAG#0 THEN  BFLAG = X'40000000'
CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_IN SOURCE)
CURRENT IN DETAILS_CLASS = BFLAG ! X'20000003'
OFFSET == CURRENT IN DETAILS_CURRENT OFFSET
IF  SSOWN_SHORT CUT#0 THEN  START 
    CURRENT IN DETAILS_BOUND = C 
        CURRENT IN DETAILS_BOUND - SSOWN_SCADDR + CURRENT IN DETAILS_ADDRESS
    CURRENT IN DETAILS_ADDRESS = SSOWN_SCADDR
    SSOWN_SHORT CUT = 0
FINISH  ELSE  START 
    CURRENT IN DETAILS_BOUND = CURRENT IN DETAILS_BOUND - OFFSET
    CURRENT IN DETAILS_ADDRESS = CURRENT IN DETAILS_ADDRESS + OFFSET
FINISH 
OFFSET = 0
CURRENT IN DETAILS_PARM COUNT = NPARM
OLD PTR = SSOWN_WSP PTR
SSOWN_WSP PTR = (SSOWN_WSP PTR+7) & (-8)
IF  NPARM>0 THEN  START 
    BEGIN 
        STRING  ARRAY  NAME  KTABLE
        RECORD (PD) NAME  COPY DEST DR
        CURRENT IN DETAILS_PARM VAL DET == ARRAY (SSOWN_WSP PTR,VAL DESC DV)
        PV COPY == ARRAY (SSOWN_WSP PTR,VAL DESC DV)
        SSOWN_WSP PTR = ADDR (PV COPY(NPARM+1))
        IF  SSOWN_WSP PTR>SSOWN_WSP LIM THEN  -> TOO BIG
        FOR  I=1,1,NPARM CYCLE 
            COPY SOURCE DR == ACTUAL PARMS (I)
            COPY DEST DR == PV COPY (I)
            J = COPY SOURCE DR_BOUND
            COPY DEST DR_BOUND = J
            COPY DEST DR_ADDRESS = SSOWN_WSP PTR
            J = J & X'00FFFFFF'
            IF  SSOWN_WSP PTR+J>SSOWN_WSP LIM THEN  -> TOO BIG
            IF  J>0 THEN  START 
                ! **** **** REPLACE BY MACHINE CODE: **** ****
                ! M = COPY SOURCE DR_ADDRESS
                ! %FOR K=0,1,J-1 %CYCLE
                !     BYTE INTEGER (SSOWN_WSP PTR+K) = BYTE INTEGER (M+K)
                ! %REPEAT
                ! EQUIVALENT TO:
                MOVE (J, COPY SOURCE DR_ADDRESS, SSOWN_WSP PTR)
                ! **** **** END OF MACHINE CODE SECTION **** ****
                SSOWN_WSP PTR = SSOWN_WSP PTR + J
            FINISH 
        REPEAT 
        SSOWN_WSP PTR = (SSOWN_WSP PTR + 7) & (-8)
        CURRENT IN DETAILS_KWDN == ARRAY (SSOWN_WSP PTR,KEY ARRAY DV)
        KTABLE == ARRAY (SSOWN_WSP PTR,KEY ARRAY DV)
        ! **** **** THIS IS ONLY NEEDED IF WE USE 'MOVE' **** ****
        KTLIM = ADDR (KTABLE(NPARM+1))
        MOVE SIZE = KTLIM - SSOWN_WSP PTR
        MOVE DEST = SSOWN_WSP PTR
        SSOWN_WSP PTR = (KTLIM + 7) & (-8) + 4; ! ROUNDED UP.
        ! **** **** THE FOLLOWING LINE IS THE ALTERNATIVE **** ****
        ! **** **** NEEDED IF WE DO THE MOVE IN A %CYCLE  **** ****
        ! SSOWN_WSP PTR = (ADDR(KTABLE(NPARM+1))+7) & (-8) + 4; ! ROUNDED UP.
        ! **** **** END OF ALTERNATIVE **** ****
        IF  SSOWN_WSP PTR>SSOWN_WSP LIM THEN  -> TOO BIG
        ! **** **** REPLACE BY MACHINE CODE: **** ****
        ! %FOR I=1,1,NPARM %CYCLE
        !     KTABLE (I) = KEYWORDS (I)
        ! %REPEAT
        ! EQUIVALENT TO:
        MOVE (MOVE SIZE, ADDR(KEYWORDS(1)), MOVE DEST)
        ! **** **** END OF MACHINE CODE SECTION **** ****
        !
        IF  DIAGOP#0 THEN  LIST PARAMETERS (NPARM,KTABLE,PV COPY)
        !
TOO BIG:
    END 
FINISH  ELSE  SSOWN_WSP PTR = SSOWN_WSP PTR + 4
IF  SSOWN_WSP PTR<=SSOWN_WSP LIM THEN  START 
    INTEGER (SSOWN_WSP PTR-4) = OLD PTR
    RETURN 
FINISH  ELSE  START 
    SSOWN_WSP PTR = OLD PTR
    SSOWN_IN SOURCE = SSOWN_IN SOURCE - 1
    FAILURE = FAILURE ! X'80000400'
    RETURN 
FINISH 
END 
!
!
SYSTEM  ROUTINE  CLEAR LEVEL (INTEGER  L)
IF  L>0 THEN  SSOWN_IN SOURCE = L - 1 ELSE  SSOWN_MAC INITIALISED = 0
SSOWN_SHORT CUT = 0
END 
!
!
SYSTEM  ROUTINE  ABANDON LEVEL
IF  SSOWN_IN SOURCE>0 C 
THEN  SSOWN_IN SOURCE = SSOWN_IN SOURCE - 1 C 
ELSE  SSOWN_MAC INITIALISED = 0
SSOWN_SHORT CUT = 0
END 
!
!
SYSTEM  ROUTINE  RESTART THIS LEVEL
SSOWN_SOURCE DETAIL(SSOWN_IN SOURCE)_CURRENT OFFSET = 0
SSOWN_SHORT CUT = 0
END 
!
!
SYSTEM  ROUTINE  GO BACK
! THIS IS FOR 'BACKWARD .GOTO'S.  IT NEEDS TO FIND THE HIGHEST CURRENT
! INPUT LEVEL EXCLUDING IMPERMANENT THINGS LIKE PARAMETER VALUES, SO IT
! LOOKS DOWN THROUGH THE LEVELS FOR A MACRO TEXT OR PERMANENT TEXT.
INTEGER  S, C, F
RECORD (SD) NAME  IN DETAILS
S = SSOWN_IN SOURCE
F = -1
WHILE  S>F CYCLE 
    IN DETAILS == SSOWN_SOURCE DETAIL (S)
    C = IN DETAILS_CLASS & X'27FFFFFF'
    IF  C=X'20000002' OR  C&X'07FFFFFF'=3 THEN  F = S
    S = S - 1
REPEAT 
IF  F>=0 THEN  START 
    IN DETAILS_CURRENT OFFSET = 0
    SSOWN_SHORT CUT = 0
FINISH 
END 
!
!
SYSTEM  INTEGER  FN  MASTER CHAR IN (INTEGER  CONTROL)
! 'MASTER CHAR IN' IS A SUBSTITUTE FOR 'READ CH' AND 'NEXT CH'.
! YOU USE
!    S = MASTER CHAR IN (1)
! INSTEAD OF
!    READ CH (S)
! AND
!    S = MASTER CHAR IN (0)
! INSTEAD OF
!    S = NEXT CH
! IF YOU WANT TO FORCE INPUT TO COME FROM THE "OUTERMOST LEVEL",
! THEN USE -1 FOR "READ CH", AND -2 FOR "NEXT CH".
! THIS ROUTINE TAKES CARE OF MACRO EXPANSION AND SO ON.  THE
! COMMENTS ON 'NEW LEVEL', 'USE AS MACRO', ETC., EXPLAIN HOW
! TO SPECIFY WHERE INPUT SHOULD COME FROM, AND HOW END-OF-INPUT
! IS TREATED.
STRING  (8) ARRAY  NAME  KWD NAME
RECORD (PD) ARRAY  NAME  PARM SPEC
! %OWN %INTEGER LIM, SCLIM, PERMANENCE, SLVL
! %OWN %INTEGER %NAME OFFSET
INTEGER  CLASS WORD, ENDACT, ENDNL, CLASS NUMBER, D
INTEGER  LOOP LIM, ADVANCE
! %OWN %RECORD(SD) %NAME CURRENT IN DETAILS
RECORD (PD) NAME  PARM DETAILS
IF  ULCEQUIV=0 THEN  START 
   STRING  NAME  KWDSTR
FINISH  ELSE  START 
   STRING  (11) KWDSTR, CHECKWDSTR; ! Max length must be =KWD MAX
FINISH 
SWITCH  HANDLE (1:3)
INTEGER  M, I, L, J, NUMBER OF PARAMS, BYTES TO TEST
!
ADVANCE = CONTROL & 1
!
IF  SSOWN_SHORT CUT#0 THEN  START 
    IF  CONTROL>=0 OR  SSOWN_SLVL=0 THEN  START 
        D = BYTE INTEGER (SSOWN_SCADDR)
        IF  D=25 THEN  START 
            SSOWN_OFFSET = SSOWN_LIM
        FINISH  ELSE  START 
            IF  SSOWN_PERMANENCE=0 C 
            THEN  SSOWN_IN CHAR ADDR = 0 C 
            ELSE  SSOWN_IN CHAR ADDR = SSOWN_SCADDR
            IF  ADVANCE#0 THEN  START 
                SSOWN_LAST CHAR READ = D
                SSOWN_SCADDR = SSOWN_SCADDR + 1
                IF  SSOWN_SCADDR>=SSOWN_SCLIM THEN  START 
                    SSOWN_OFFSET = SSOWN_LIM
                    SSOWN_SHORT CUT = 0
                FINISH 
            FINISH 
            RESULT  = D
        FINISH 
    FINISH  ELSE  START 
        SSOWN_OFFSET = SSOWN_SCADDR - SSOWN_CURRENT IN DETAILS_ADDRESS
    FINISH 
FINISH 
SSOWN_SHORT CUT = 0
!
! THIS ROUTINE IS AN ENDLESS CYCLE, FROM WHICH THE ONLY
! ESCAPE IS BY %RESULT = SOMETHING.  WITHIN THE CYCLE, CONTROL
! IS SWITCHED TO ONE OF THREE POINTS DEPENDING ON THE NATURE
! OF THE PROCESSING APPROPRIATE TO THE CURRENT INPUT LEVEL.
! THE ONLY 'GOTO' IS AT THE END OF EACH PROCESSING SECTION TO
! GET TO THE BOTTOM OF THE LOOP.
CYCLE 
!
IF  CONTROL<0 THEN  SSOWN_SLVL = 0 ELSE  SSOWN_SLVL = SSOWN_IN SOURCE
SSOWN_CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_SLVL)
CLASS WORD = SSOWN_CURRENT IN DETAILS_CLASS
ENDACT = CLASS WORD & X'80000000'
ENDNL = CLASS WORD & X'10000000'
SSOWN_PERMANENCE = CLASS WORD & X'20000000'
CLASS NUMBER = CLASS WORD & X'07FFFFFF'
-> HANDLE (CLASS NUMBER)
!
HANDLE (1): ! INPUT FROM CONTROL STREAM -
! IF THERE IS ANY POSSIBILITY THAT 'READ CH' AND 'NEXT CH' WOULD
! BE USED ON SOME FILE OTHER THAN A CONSOLE INPUT STREAM, THE FOLLOWING
! CODE SHOULD BE MODIFIED TO MAKE SURE THAT %EVENT 9 COULD NEVER BE
! CAUSED, SINCE THE CODE IS NOT PROTECTED AGAINST THAT CONTINGENCY.
! THE WAY TO DO IT IS TO DECLARE
! %OWN %INTEGER DREAD=0
! AT THE HEAD OF THIS ROUTINE, AND THEN REPLACE THE CODE BELOW (FROM
! %IF ADVANCE... TO %RESULT = D) BY:
! %IF DREAD#25 %THEN %START
!    %IF ADVANCE=0 %THEN DREAD = JOB NEXT CH %ELSE %START
!        DREAD = JOB READ CH
!        SSOWN_LAST CHAR READ = DREAD
!    %FINISH
! %FINISH
! %RESULT = DREAD
!
SSOWN_IN CHAR ADDR = 0
IF  ADVANCE=0 THEN  D = JOB NEXT CH ELSE  START 
    D = JOB READ CH
    SSOWN_LAST CHAR READ = D
FINISH 
RESULT  = D
!
HANDLE (2): ! INPUT FROM A FILE OR STRING -
SSOWN_OFFSET == SSOWN_CURRENT IN DETAILS_CURRENT OFFSET
SSOWN_LIM = SSOWN_CURRENT IN DETAILS_BOUND & X'00FFFFFF'
IF  SSOWN_OFFSET>=SSOWN_LIM THEN  START 
    IF  ENDACT#0 THEN  START 
        SSOWN_IN CHAR ADDR = 0
        IF  ADVANCE#0 THEN  SSOWN_LAST CHAR READ = NL
        IF  ENDNL#0 AND  SSOWN_OFFSET=SSOWN_LIM AND  SSOWN_LIM>0 C 
        AND  BYTE INTEGER(SSOWN_CURRENT IN DETAILS_ADDRESS+SSOWN_LIM-1)#NL C 
        THEN  START 
            SSOWN_OFFSET = SSOWN_OFFSET + ADVANCE
            RESULT  = NL
        FINISH 
        RESULT  = 25
    FINISH 
    SSOWN_IN SOURCE = SSOWN_IN SOURCE - 1
FINISH  ELSE  START 
    SSOWN_IN CHAR ADDR = SSOWN_CURRENT IN DETAILS_ADDRESS+SSOWN_OFFSET
    D = BYTE INTEGER (SSOWN_IN CHAR ADDR)
    IF  D=25 THEN  START 
        SSOWN_OFFSET = SSOWN_LIM
    FINISH  ELSE  START 
        SSOWN_OFFSET = SSOWN_OFFSET + ADVANCE
        IF  SSOWN_OFFSET<SSOWN_LIM THEN  START 
            SSOWN_SHORT CUT = -1
            SSOWN_SCADDR = SSOWN_IN CHAR ADDR + ADVANCE
            SSOWN_SCLIM = SSOWN_CURRENT IN DETAILS_ADDRESS + SSOWN_LIM
        FINISH 
        IF  SSOWN_PERMANENCE=0 THEN  SSOWN_IN CHAR ADDR = 0
        IF  ADVANCE#0 THEN  SSOWN_LAST CHAR READ = D
        RESULT  = D
    FINISH 
FINISH 
-> LOOP END
!
HANDLE (3): ! INPUT FROM A MACRO EXPANSION -
KWD NAME == SSOWN_CURRENT IN DETAILS_KWDN
PARM SPEC == SSOWN_CURRENT IN DETAILS_PARM VAL DET
NUMBER OF PARAMS = SSOWN_CURRENT IN DETAILS_PARM COUNT
SSOWN_OFFSET == SSOWN_CURRENT IN DETAILS_CURRENT OFFSET
SSOWN_LIM = SSOWN_CURRENT IN DETAILS_BOUND & X'00FFFFFF'
IF  SSOWN_OFFSET>=SSOWN_LIM THEN  START 
    SSOWN_BRACKET FLAG = CLASS WORD&X'40000000'
    IF  ENDACT#0 THEN  START 
        SSOWN_IN CHAR ADDR = 0
        IF  ADVANCE#0 THEN  SSOWN_LAST CHAR READ = NL
        RESULT  = 25
    FINISH 
    SSOWN_WSP PTR = INTEGER (SSOWN_WSP PTR-4)
    SSOWN_IN SOURCE = SSOWN_IN SOURCE - 1
FINISH  ELSE  START 
    SSOWN_IN CHAR ADDR = SSOWN_CURRENT IN DETAILS_ADDRESS + SSOWN_OFFSET
    BYTES TO TEST = SSOWN_LIM - SSOWN_OFFSET
    IF  BYTES TO TEST>KWD MAX+LENGTH(EXPANDER) C 
    THEN  BYTES TO TEST = KWD MAX + LENGTH(EXPANDER)
    D = BYTE INTEGER (SSOWN_IN CHAR ADDR)
    IF  D=25 THEN  START 
        SSOWN_OFFSET = SSOWN_LIM
    FINISH  ELSE  START 
        LOOP LIM = NUMBER OF PARAMS
        ! **** **** THIS TEST WOULD NEED TO BE EXPANDED IF **** ****
        ! **** **** LENGTH(EXPANDER)>2                     **** ****
        IF  D=BYTE INTEGER(ADDR(EXPANDER)+1) C 
        AND  NUMBER OF PARAMS>=1 C 
        AND  BYTES TO TEST>=LENGTH(EXPANDER)+1 C 
        AND  BYTE INTEGER(SSOWN_IN CHAR ADDR+1) C 
            =BYTE INTEGER(ADDR(EXPANDER)+2) C 
        THEN  START 
            M = BYTES TO TEST - 2
            I = 1
            WHILE  I<=LOOP LIM CYCLE 
               IF  ULCEQUIV=0 THEN  START 
                  KWDSTR == KWD NAME (I)
               FINISH  ELSE  START 
                  KWDSTR = KWD NAME (I)
               FINISH 
                L = LENGTH (KWDSTR); ! MUST NEVER BE LESS THAN 1.
                IF  M>=L THEN  START 
                    IF  ULCEQUIV=0 THEN  START 
                       ! **** **** REPLACE BY MACHINE CODE **** ****
                       J = 1
                       WHILE  J<=L C 
                       AND  BYTE INTEGER(ADDR(KWDSTR)+J) C 
                           =BYTE INTEGER(SSOWN_IN CHAR ADDR+J+1) C 
                       CYCLE 
                           J = J + 1
                       REPEAT 
                       ! **** **** END OF MACHINE CODE SECTION **** ****
                       IF  J>L THEN  START 
                           SSOWN_OFFSET = SSOWN_OFFSET + L + 2
                           PARM DETAILS == PARM SPEC (I)
                           SSOWN_IN SOURCE = SSOWN_IN SOURCE + 1
                           SSOWN_CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_IN SOURCE)
                           SSOWN_CURRENT IN DETAILS_BOUND = PARM DETAILS_BOUND
                           SSOWN_CURRENT IN DETAILS_ADDRESS = C 
                               PARM DETAILS_ADDRESS
                           SSOWN_CURRENT IN DETAILS_CURRENT OFFSET = 0
                           SSOWN_CURRENT IN DETAILS_CLASS = 2
                           LOOP LIM = -1; ! TO FORCE EXIT.
                       FINISH 
                    FINISH  ELSE  START 
                       UCTRANSLATE (ADDR(KWDSTR)+1,L)
                       MOVE (L, SSOWN_IN CHAR ADDR + 2, ADDR(CHECKWDSTR) + 1)
                       UCTRANSLATE (ADDR(CHECKWDSTR)+1, L)
                       LENGTH (CHECKWDSTR) = L
                       IF  CHECKWDSTR=KWDSTR THEN  START 
                           SSOWN_OFFSET = SSOWN_OFFSET + L + 2
                           PARM DETAILS == PARM SPEC (I)
                           SSOWN_IN SOURCE = SSOWN_IN SOURCE + 1
                           SSOWN_CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (SSOWN_IN SOURCE)
                           SSOWN_CURRENT IN DETAILS_BOUND = PARM DETAILS_BOUND
                           SSOWN_CURRENT IN DETAILS_ADDRESS = C 
                               PARM DETAILS_ADDRESS
                           SSOWN_CURRENT IN DETAILS_CURRENT OFFSET = 0
                           SSOWN_CURRENT IN DETAILS_CLASS = 2
                           LOOP LIM = -1; ! TO FORCE EXIT.
                       FINISH 
                    FINISH 
                FINISH 
                I = I + 1
            REPEAT 
        FINISH 
        IF  LOOP LIM>=0 THEN  START 
            IF  SSOWN_PERMANENCE=0 THEN  SSOWN_IN CHAR ADDR = 0
            SSOWN_OFFSET = SSOWN_OFFSET + ADVANCE
            IF  ADVANCE#0 THEN  SSOWN_LAST CHAR READ = D
            RESULT  = D
        FINISH 
    FINISH 
FINISH 
!
LOOP END:
REPEAT 
! THIS IS THE END OF THE MAIN LOOP OF THIS ROUTINE.
!
END 
!
!
IF  DIAGOP#0 THEN  START 
   EXTERNAL  ROUTINE  PRINT LEVELS
   RECORD (SD) NAME  CURRENT IN DETAILS
   INTEGER  LEVEL, CLASS WORD, CLASS NUMBER, ENDACT, PERMANENCE
   INTEGER  REVERSION
   PRINT STRING ("INPUT MAP:".TOSTRING(NL))
   FOR  LEVEL=SSOWN_IN SOURCE,-1,0 CYCLE 
     PRINT STRING ("LEVEL")
     PRINT (LEVEL,3,0)
     CURRENT IN DETAILS == SSOWN_SOURCE DETAIL (LEVEL)
     CLASS WORD = CURRENT IN DETAILS_CLASS
     ENDACT = CLASS WORD & X'80000000'
     REVERSION = CLASS WORD & X'40000000'
     PERMANENCE = CLASS WORD & X'20000000'
     CLASS NUMBER = CLASS WORD & X'07FFFFFF'
     IF  CLASS NUMBER = 1 THEN  START 
         PRINT STRING (": DIRECT INPUT".TOSTRING(NL))
     FINISH  ELSE  START 
         IF  CLASS NUMBER = 2 THEN  START 
             PRINT STRING (": TEXT, AT ")
         FINISH  ELSE  START 
             PRINT STRING (": MACRO, AT ")
         FINISH 
         PRINT (CURRENT IN DETAILS_ADDRESS,12,0)
         PRINT STRING ("    LENGTH ")
         PRINT (CURRENT IN DETAILS_BOUND&X'00FFFFFF',9,0)
         NEWLINE
     FINISH 
   REPEAT 
   END 
FINISH 
!
!
SYSTEM  INTEGER  FN  LAST CHAR COPY
   RESULT  = SSOWN_LAST CHAR READ
END 
!
!
END  OF  FILE