CONSTINTEGER  NEWLOADER=1;  ! 0 for old loader, 1 for new loader
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.
!
IF  ULCEQUIV#0 THEN  START 
   SYSTEM  ROUTINE  SPEC  CAST OUT (STRING  NAME  PSTR)
   SYSTEM  ROUTINE  SPEC  UCTRANSLATE (INTEGER  A, L)
FINISH 
!
! Constants and extrinsics used by NEW loader
IF  NEWLOADER#0 THEN  START 
   CONSTINTEGER  CODE=2
   CONSTINTEGER  MACRO=4
!    %EXTRINSICINTEGER LOADLEVEL
!    %EXTRINSICINTEGER SSCURBGLA
FINISH 
!
INCLUDE  "SS0302S_SSOWNF"
!
RECORD  FORMAT  HF (INTEGER  DATAEND, DATASTART, FILESIZE, FILETYPE, C 
    SUM, DATETIME, FORMAT, RECORDS)
RECORD  FORMAT  RF (INTEGER  ADDR, TYPE, START, LIMIT)
! %RECORD %FORMAT PD (%INTEGER BOUND, ADDRESS)
RECORD  FORMAT  FRF(INTEGER  CONAD,FILETYPE,DATASTART,DATEND,C 
    SIZE,RUP,EEP,MODE,USERS,ARCH,STRING (6)TRAN,STRING (8)DATE,TIME,C 
    INTEGER  COUNT,SPARE1,SPARE2)
SYSTEM  ROUTINE  SPEC  FINFO(STRING (31)FILE,INTEGER  MODE,C 
    RECORD (FRF)NAME  R,INTEGERNAME  FLAG)
SYSTEM  ROUTINE  SPEC  MOVE (INTEGER  LENGTH, FROM, TO)
SYSTEM  ROUTINE  SPEC  CONNECT (STRING  (31) NAME, C 
    INTEGER  MODE, HOLE, PROT, C 
    RECORD (RF)NAME  RR, INTEGER  NAME  FLAG)
SYSTEM  ROUTINE  SPEC  DISCONNECT (STRING  (31) FILE, INTEGER  NAME  F)
SYSTEM  ROUTINE  SPEC  OUTFILE C 
    (STRING  (31) FILE, INTEGER  BYTES, HOLE, PROT, C 
     INTEGER  NAME  CONADDR, FLAG)
   SYSTEM  INTEGER  FN  SPEC  C 
STARTSWITH (STRING  NAME  A, STRING  (255) B, INTEGER  CHOP)
SYSTEM  INTEGER  MAP  SPEC  COMREG (INTEGER  N)
SYSTEM  ROUTINE  SPEC  HASH COMMAND (STRING  (255) COMMAND, PARMS)
IF  NEWLOADER=0 THEN  START 
   SYSTEM  ROUTINE  SPEC  LOAD COMMAND C 
       (STRING  (31) NAME, STRING  NAME  ALIAS, C 
        INTEGER  NAME  TYPE, DR0, DR1, FLAG)
FINISH  ELSE  START 
   SYSTEMLONGINTEGERFNSPEC  LOADEP C 
      (STRING (31) NAME, INTEGERNAME  TYPE,FLAG, INTEGER  LOADLEVEL)
FINISH 
SYSTEM  ROUTINE  SPEC  BEFORE COMMAND
SYSTEM  ROUTINE  SPEC  ENTER (INTEGER  CLASS, DR0, DR1, STRING  (255) P)
SYSTEM  ROUTINE  SPEC  AFTER COMMAND
EXTERNAL  ROUTINE  SPEC  PROMPT (STRING  (15) S)
EXTERNAL  ROUTINE  SPEC  SET RETURN CODE (INTEGER  N)
EXTERNAL  INTEGER  FN  SPEC  UINFI (INTEGER  TYPE)
!
!
! INPUT AND MACRO EXPANSION ROUTINES:
SYSTEM  INTEGER  FN  SPEC  MASTER CHAR IN (INTEGER  ADVANCE)
! %EXTRINSIC %INTEGER LAST CHAR READ
! %EXTRINSIC %INTEGER IN CHAR ADDR
! %EXTRINSIC %INTEGER KWD MAX SIZE
! %EXTRINSIC %INTEGER MAC INITIALISED
! %EXTRINSIC %INTEGER IN SOURCE
SYSTEM  ROUTINE  SPEC  START MACROUTINES C 
    (INTEGER  BOUND, ADDRESS, INTEGER  NAME  R)
SYSTEM  ROUTINE  SPEC  NEW LEVEL C 
   (INTEGER  BOUND, ADDRESS, EOFACT, INTEGER  NAME  R)
SYSTEM  ROUTINE  SPEC  USE AS MACRO (INTEGER  NPARM, C 
    STRING  ARRAY  NAME  KEYWORDS, C 
    RECORD (PD) ARRAY  NAME  ACTUAL PARMS, C 
    INTEGER  BFLAG, INTEGER  NAME  FAILURE)
SYSTEM  ROUTINE  SPEC  ABANDON LEVEL
SYSTEM  ROUTINE  SPEC  CLEAR LEVEL (INTEGER  L)
SYSTEM  ROUTINE  SPEC  GO BACK
SYSTEM  ROUTINE  SPEC  RESTART THIS LEVEL
IF  DIAGOP#0 THEN  START 
   EXTERNAL  ROUTINE  SPEC  PRINT LEVELS
   EXTERNAL  ROUTINE  SPEC  LIST PARAMETERS C 
    (INTEGER  P, C 
     STRING  ARRAY  NAME  KNAME, C 
     RECORD (PD) ARRAY  NAME  VALUE)
FINISH 
!
! PARAMETER STRING PROCESSING ROUTINES:
SYSTEM  ROUTINE  SPEC  ANALYSE PARAMETERS C 
    (STRING  NAME  DCL PARMS, CALL PARMS, INTEGER  MAX PARMS, C 
     STRING   ARRAY  NAME  KEYS, INTEGER  MAX KEY SIZE, C 
     RECORD  (PD) ARRAY  NAME  ACTUAL, C 
     INTEGER  NAME  TOTAL KEYS, RESPONSE)
!
ROUTINE  APARAM C 
    (STRING  NAME  DCL PARMS, CALL PARMS, INTEGER  MAX PARMS, C 
     STRING   ARRAY  NAME  KEYS, INTEGER  MAX KEY SIZE, C 
     RECORD  (PD) ARRAY  NAME  ACTUAL, C 
     INTEGER  NAME  TOTAL KEYS, RESPONSE)
!
! When ANALYSE PARAMETERS was moved into the subsystem basefile, it was
! changed so that, where a parameter was not given a value in the call
! nor as a default, the corresponding ACTUAL(..)_BOUND would be set to
! -1 instead of to zero (which would mean that a null string had been
! specified).  Rather than making consequential changes throughout CLI,
! I simply replaced all calls on ANALYSE PARAMETERS by calls on APARAM,
! and this routine APARAM simply calls ANALYSE PARAMETERS and then clears
! any BOUNDs which are -1.
!
INTEGER  I
      ANALYSE PARAMETERS (DCL PARMS, CALL PARMS, MAX PARMS, KEYS, C 
         MAX KEY SIZE, ACTUAL, TOTAL KEYS, RESPONSE)
      I = 1
      WHILE  I<=TOTAL KEYS CYCLE 
         IF  ACTUAL(I)_BOUND=-1 THEN  ACTUAL(I)_BOUND = 0
         I = I + 1
      REPEAT 
END 
!
CONST  INTEGER  KWDS = 7
! 'RECOGNISE KWDS' CAN GIVE RESULTS IN THE RANGE 0 TO KWDS.
! %OWN %STRING (5) SPECHARS
! %OWN %STRING (3) CONTU
! %OWN %STRING (3) XSTMT
! %OWN %STRING (1) NULLSTRING = ""
CONST  STRING  (5) STARS = "**** "
!
!
! ERROR MESSAGES CAN BE PRINTED BY THE ROUTINE 'PRINT ERRORS', WHICH
! TAKES TWO PARAMETERS: A WORD IN WHICH EACH BIT SIGNIFIES AN ERROR
! WHICH HAS OCCURRED IF THE BIT IS ONE, AND NO ERROR IF IT IS ZERO;
! AND A %BYTE %INTEGER %ARRAY %NAME WHICH DEFINES THE MESSAGES TO BE
! PRINTED FOR EACH ERROR.  THE ARRAY MUST BE ONE-DIMENSIONAL WITH
! LOWER BOUND ZERO, AND IT IS LAID OUT LIKE THIS:
! BYTES 32 ONWARDS CONTAIN THE VARIOUS STRINGS, IN ANY ORDER.
! THEY MAY, BUT THEY NEED NOT, BE PACKED CLOSE UP TOGETHER, OR
! THERE MAY BE UNUSED BYTES BETWEEN ANY STRING AND THE NEXT.
! EACH STRING CONSISTS (SURPRISE, SURPRISE!) OF A LENGTH BYTE
! FOLLOWED BY THE ISO CHARACTERS - I.E., THE NORMAL IMP %STRING.
! BYTES 0 TO 31 CORRESPOND TO THE BITS OF THE FLAG WORD.  BYTE 0
! CORRESPONDS TO THE LEAST SIGNIFICANT BIT AND BYTE 31 TO THE
! MOST SIGNIFICANT BIT OF THE WORD.  THUS THE NUMBERING OF THE
! BYTES IS NOT THE SAME AS THE NUMBERING OF THE BITS, AND I DON'T
! CARE.  EACH BYTE IS ZERO IF THERE IS NO TEXT FOR THE CORRESPONDING
! BIT, OR (N-31) IF THE TEXT STRING STARTS IN ELEMENT (N) OF
! THE ARRAY.
!
!
!
ROUTINE  PRINT ERRORS C 
    (INTEGER  A, BYTE  INTEGER  ARRAY  NAME  MSGD)
INTEGER  I, Q
FOR  I=0,1,31 CYCLE 
    IF  A&1#0 THEN  START 
        Q = MSGD (I)
        IF  Q#0 THEN  START 
            PRINT STRING (STARS)
            PRINT STRING (STRING(ADDR(MSGD(31+Q))))
            NEWLINE
        FINISH 
    FINISH 
    A = A >> 1
REPEAT 
END 
!
!
!  BIT             TEXT
! VALUE
!   1      "BRACKETS OR QUOTES IN PREDICATE"
!   2      "PREDICATE MISSING"
!   4      "UNRECOGNISED NAME IN PREDICATE"
!   8      "INVALID COMPARATOR"
!   16     "INVALID INTEGER"
!   32     "LOGICAL INSTEAD OF INTEGER"
!   64     "INTEGER INSTEAD OF LOGICAL"
!   128    "PREDICATE INVALID FOR WHENEVER"
CONST  BYTE  INTEGER  ARRAY  PRED ETEXTS (0:232) = C 
     1,  33,  51,  82, 101, 117, 144, 171,
     0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,
31, 'B','r','a','c','k','e','t','s',
    ' ','o','r',
    ' ','q','u','o','t','e','s',
    ' ','i','n',
    ' ','p','r','e','d','i','c','a','t','e',
17, 'P','r','e','d','i','c','a','t','e',
    ' ','m','i','s','s','i','n','g',
30, 'U','n','r','e','c','o','g','n','i','s','e','d',
    ' ','n','a','m','e',
    ' ','i','n',
    ' ','p','r','e','d','i','c','a','t','e',
18, 'I','n','v','a','l','i','d',
    ' ','c','o','m','p','a','r','a','t','o','r',
15, 'I','n','v','a','l','i','d',
    ' ','i','n','t','e','g','e','r',
26, 'L','o','g','i','c','a','l',
    ' ','i','n','s','t','e','a','d',
    ' ','o','f',
    ' ','i','n','t','e','g','e','r',
26, 'I','n','t','e','g','e','r',
    ' ','i','n','s','t','e','a','d',
    ' ','o','f',
    ' ','l','o','g','i','c','a','l',
30, 'P','r','e','d','i','c','a','t','e',
    ' ','i','n','v','a','l','i','d',
    ' ','f','o','r',
    ' ','W','H','E','N','E','V','E','R'
!
!
!        BIT              TEXT
!       VALUE
!    X'00000001'   "KEYWORD MISSING"
!    X'00000004'   "TOO MANY PARAMETER FIELDS"
!    X'00000080'   "KEYWORDS NOT DISTINCT IN HEADER"
!    X'00000400'   "WORK AREA TOO FULL"
!    X'00000800'   "CANNOT RECOGNISE HEADER"
!    X'00001000'   "TOO MANY INPUT LEVELS"
!    X'00002000'   "NO TEXT"
!    X'00004000'   "WORK SPACE EXHAUSTED"
!    X'00008000'   "NO NAME"
!    X'00010000'   "TOO MANY MACROS"
CONST  BYTE  INTEGER  ARRAY  MACRO ETEXTS (0:223) = C 
      1,   0,  17,   0,   0,   0,   0, 161,
      0,   0,  43,  62,  86, 108, 116, 137,
    145,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   0,   0,   0,   0,   0,   0,
15, 'K','e','y','w','o','r','d',' ','m','i','s','s','i','n','g',
25, 'T','o','o',' ','m','a','n','y',
    ' ','p','a','r','a','m','e','t','e','r',' ','f','i','e','l','d','s',
18, 'W','o','r','k',' ','a','r','e','a',' ','t','o','o',
    ' ','f','u','l','l',
23, 'C','a','n','n','o','t',' ','r','e','c','o','g','n','i','s','e',
    ' ','h','e','a','d','e','r',
21, 'T','o','o',' ','m','a','n','y',' ','i','n','p','u','t',
    ' ','l','e','v','e','l','s',
 7, 'N','o',' ','t','e','x','t',
20, 'W','o','r','k',' ','s','p','a','c','e',
    ' ','e','x','h','a','u','s','t','e','d',
 7, 'N','o',' ','n','a','m','e',
15, 'T','o','o',' ','m','a','n','y',' ','m','a','c','r','o','s',
31, 'K','e','y','w','o','r','d','s',
    ' ','n','o','t',
    ' ','d','i','s','t','i','n','c','t',
    ' ','i','n',
    ' ','h','e','a','d','e','r'
!
!  BIT          TEXT
! VALUE
!   1   "KWD MISSING IN DECLN"
!   2   "KWD TOO LONG IN DECLN"
!   4   "TOO MANY FIELDS IN DECLN"
!   8   "KWD TOO LONG IN CALL"
!  16   "UNKNOWN KWD IN CALL"
!  32   "PARAMETER SPECIFIED TWICE"
!  64   "WRAP-AROUND"
! 128   "INDISTINCT KWDS IN HEADER"
CONST  BYTE  INTEGER  ARRAY  PARAM ETEXTS (0:204) = C 
     1,  22,  44,  69,  90, 110, 136, 148,
     0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,
20, 'K','w','d',
    ' ','m','i','s','s','i','n','g',
    ' ','i','n',
    ' ','d','e','c','l','n',
21, 'K','w','d',
    ' ','t','o','o',
    ' ','l','o','n','g',
    ' ','i','n',
    ' ','d','e','c','l','n',
24, 'T','o','o',
    ' ','m','a','n','y',
    ' ','f','i','e','l','d','s',
    ' ','i','n',
    ' ','d','e','c','l','n',
20, 'K','w','d',
    ' ','t','o','o',
    ' ','l','o','n','g',
    ' ','i','n',
    ' ','c','a','l','l',
19, 'U','n','k','n','o','w','n',
    ' ','k','w','d',
    ' ','i','n',
    ' ','c','a','l','l',
25, 'P','a','r','a','m','e','t','e','r',
    ' ','s','p','e','c','i','f','i','e','d',
    ' ','t','w','i','c','e',
11, 'W','r','a','p','-','a','r','o','u','n','d',
25, 'I','n','d','i','s','t','i','n','c','t',
    ' ','k','w','d','s',
    ' ','i','n',
    ' ','h','e','a','d','e','r'
!
CONST  STRING  (5) DATA START MARK = ".DATA"
CONST  STRING  (3) DATA END MARK = ".ED"
! %OWN %STRING (80) D DELIM 1 = ".DATA", D DELIM 2 = ".ED"
! %OWN %INTEGER COMMENTF
!
!
!
! %OWN %INTEGER SAVE BASE = 0
! %OWN %INTEGER WARNING NUMBER = 0, SAVE LIM, SAVE PTR
! %OWN %INTEGER ACCUMULATING, STATE = 1
! %OWN %RECORD(PD) ACCUMULATION
! %OWN %INTEGER LAST PROMPT
!
! %ROUTINE TIDY ACCUMULATION (%INTEGER DISCARD)
!    DISCARD IS THE NUMBER OF CHARACTERS TO THROW AWAY FROM
!    THE END OF THE FILE.
! ACCUMULATING = 0
! ACCUMULATION_BOUND = (ACCUMULATION_BOUND - DISCARD) ! X'18000000'
! %IF DIAGOP#0 %THEN %START
!    PRINT STRING ("++++ TIDY ACCUMULATION called.")
!    NEWLINE
! %FINISH
! %END
!
! %ROUTINE SAVE SYMBOL (%INTEGER SYMB)
! %INTEGER FINAL BOUND, FINAL ADDR
! ! %INTEGER J; ! ONLY NEEDED IF WE DO NOT USE MOVE.
! !
! ! THIS ASSUMES WHAT IS IN FACT TRUE - BUT WILL IT ALWAYS BE
! ! TRUE? - THAT ACCUMULATION_BOUND HAS NOTHING IN ITS TOP BYTE.
! %IF ACCUMULATING=0 %THEN %START
!     ACCUMULATING = -1
!     FINAL BOUND = 1
!     FINAL ADDR = SSOWN_IN CHAR ADDR
!     %IF FINAL ADDR=0 %AND SSOWN_SAVE PTR<SSOWN_SAVE LIM %THEN %START
!         FINAL ADDR = SSOWN_SAVE PTR
!         BYTE INTEGER (FINAL ADDR) = SYMB
!         SSOWN_SAVE PTR = FINAL ADDR + 1
!     %FINISH
!     ACCUMULATION_ADDRESS = FINAL ADDR
! %FINISH %ELSE %START
!     FINAL BOUND = ACCUMULATION_BOUND + 1
!     FINAL ADDR = ACCUMULATION_ADDRESS + ACCUMULATION_BOUND
!     %IF FINAL ADDR#SSOWN_IN CHAR ADDR %THEN %START
!         %IF FINAL ADDR#SSOWN_SAVE PTR %THEN %START
!             FINAL ADDR = SSOWN_SAVE PTR + ACCUMULATION_BOUND
!             %IF FINAL ADDR<SSOWN_SAVE LIM %THEN %START
!             !   %FOR J=0,1,ACCUMULATION_BOUND-1 %CYCLE
!             !       BYTE INTEGER (SSOWN_SAVE PTR + J) %C
!             !     = BYTE INTEGER (ACCUMULATION_ADDRESS + J)
!             !   %REPEAT
!             ! EQUIVALENT TO:
!                 MOVE (ACCUMULATION_BOUND,ACCUMULATION_ADDRESS,SSOWN_SAVE PTR)
!                 ACCUMULATION_ADDRESS = SSOWN_SAVE PTR
!             %FINISH
!         %FINISH
!         %IF FINAL ADDR<SSOWN_SAVE LIM %THEN %START
!             BYTE INTEGER (FINAL ADDR) = SYMB
!             SSOWN_SAVE PTR = FINAL ADDR + 1
!         %FINISH %ELSE %START
!             ACCUMULATION_ADDRESS = 0
!         %FINISH
!     %FINISH
! %FINISH
! ACCUMULATION_BOUND = FINAL BOUND
! %END
!
ROUTINE  GATHER DATA (STRING  NAME  DELIMITER, INTEGER  GC)
    ! GC=1 FOR 'SKIP DATA'.
    ! GC=2 FOR 'ADD DATA TO ACCUMULATION' - I.E., SAVE THE
    !      DATA BUT DON'T DO THE 'TIDY ACCUMULATION'
    !      UNLESS YOU FIND END-OF-FILE.
    ! GC=3 FOR 'ACCUMULATE DATA'.
    INTEGER  FINAL BOUND, FINAL ADDR, DISCARD
    ! %INTEGER J; ! ONLY NEEDED IF WE DO NOT USE MOVE.
    INTEGER  S, LINE POS, MATCHES EOD, TARGET
    !
    !
    IF  SSOWN_ACCUMULATING#0 THEN  FINAL BOUND = SSOWN_ACCUMULATION_BOUND
    ! THAT IS NOT STRICTLY NECESSARY IF GC=1, BUT I DON'T
    ! THINK YOU COULD HAVE GC=1 %AND SSOWN_ACCUMULATING#0
    ! IN FACT, AND IN ANY CASE THE ASSIGNMENT WOULD BE
    ! HARMLESS.  I BELIEVE THAT SSOWN_ACCUMULATING WILL BE
    ! NON-ZERO ONLY IF GC=2 ON ENTRY.  THE TEST FOR
    ! SSOWN_ACCUMULATING#0 IS NECESSARY BECAUSE SSOWN_ACCUMULATION
    ! IS UNASSIGNED ON FIRST ENTRY TO THE INTERPRETER.
    IF  GC=3 THEN  START 
        WHILE  NL#SSOWN_LAST CHAR READ#25 CYCLE 
            DISCARD = MASTER CHAR IN (1)
        REPEAT 
    FINISH 
    LINE POS = 1
    MATCHES EOD = -1
    WHILE  1<=GC<=3 CYCLE 
        S = MASTER CHAR IN (1)
        IF  S=25 THEN  START 
            IF  SSOWN_ACCUMULATING#0 THEN  START ; ! TIDY SSOWN_ACCUMULATION (0)
                SSOWN_ACCUMULATING = 0
                SSOWN_ACCUMULATION_BOUND = FINAL BOUND ! X'18000000'
            FINISH 
            SSOWN_WARNING NUMBER = 15
            SSOWN_STATE = 10; ! CLOSING DOWN
            GC = 0; ! TO FORCE EXIT FROM 'GATHER DATA'.
        FINISH  ELSE  START 
            IF  GC#1 THEN  START ; ! SAVE SYMBOL (S)
! <<<< <<<< <<<<
!
! THIS ASSUMES WHAT IS IN FACT TRUE - BUT WILL IT ALWAYS BE
! TRUE? - THAT SSOWN_ACCUMULATION_BOUND HAS NOTHING IN ITS TOP BYTE.
IF  SSOWN_ACCUMULATING=0 THEN  START 
    SSOWN_ACCUMULATING = -1
    FINAL BOUND = 1
    FINAL ADDR = SSOWN_IN CHAR ADDR
    IF  FINAL ADDR=0 AND  SSOWN_SAVE PTR<SSOWN_SAVE LIM THEN  START 
        FINAL ADDR = SSOWN_SAVE PTR
        BYTE INTEGER (FINAL ADDR) = S
        SSOWN_SAVE PTR = FINAL ADDR + 1
    FINISH 
    SSOWN_ACCUMULATION_ADDRESS = FINAL ADDR
FINISH  ELSE  START 
    FINAL ADDR = SSOWN_ACCUMULATION_ADDRESS + FINAL BOUND
    IF  FINAL ADDR#SSOWN_IN CHAR ADDR THEN  START 
        IF  FINAL ADDR#SSOWN_SAVE PTR THEN  START 
            FINAL ADDR = SSOWN_SAVE PTR + FINAL BOUND
            IF  FINAL ADDR<SSOWN_SAVE LIM THEN  START 
            !   %FOR J=0,1,FINAL BOUND-1 %CYCLE
            !       BYTE INTEGER (SSOWN_SAVE PTR + J) %C
            !     = BYTE INTEGER (SSOWN_ACCUMULATION_ADDRESS + J)
            !   %REPEAT
            ! EQUIVALENT TO:
                MOVE (FINAL BOUND,SSOWN_ACCUMULATION_ADDRESS,SSOWN_SAVE PTR)
                SSOWN_ACCUMULATION_ADDRESS = SSOWN_SAVE PTR
            FINISH 
        FINISH 
        IF  FINAL ADDR<SSOWN_SAVE LIM THEN  START 
            BYTE INTEGER (FINAL ADDR) = S
            SSOWN_SAVE PTR = FINAL ADDR + 1
        FINISH  ELSE  START 
            SSOWN_ACCUMULATION_ADDRESS = 0
        FINISH 
    FINISH 
    FINAL BOUND = FINAL BOUND + 1
FINISH 
! >>>> >>>> >>>>
            FINISH 
            IF  S#NL THEN  START 
                IF  MATCHES EOD#0 THEN  START 
                    IF  LINE POS<=LENGTH(DELIMITER) THEN  START 
                        TARGET = BYTE INTEGER C 
                            (ADDR(DELIMITER)+LINE POS)
                    FINISH  ELSE  START 
                        TARGET = ' '
                    FINISH 
                    IF  S#TARGET THEN  MATCHES EOD = 0
                FINISH 
            FINISH  ELSE  START 
                IF  MATCHES EOD=0 C 
                OR  LINE POS<=LENGTH(DELIMITER) C 
                THEN  START 
                    LINE POS = 0
                    MATCHES EOD = -1
                FINISH  ELSE  START 
                    IF  GC=2 THEN  SSOWN_ACCUMULATION_BOUND = FINAL BOUND
                    IF  GC=3 C 
                    THEN  START ; ! TIDY SSOWN_ACCUMULATION (LINE POS)
                        SSOWN_ACCUMULATING = 0
                        SSOWN_ACCUMULATION_BOUND = C 
                            (FINAL BOUND-LINE POS) ! X'18000000'
                    FINISH 
                    SSOWN_WARNING NUMBER = 0
                    GC = 0; ! TO FORCE EXIT.
                FINISH 
            FINISH 
            LINE POS = LINE POS + 1
        FINISH 
    REPEAT 
END 
!
ROUTINE  DISCARD DATA HEADER (STRING  NAME  HDR)
INTEGER  DLSIZE, BOUND, I, L, C, A
A = SSOWN_ACCUMULATION_ADDRESS
BOUND = SSOWN_ACCUMULATION_BOUND & X'00FFFFFF'
DLSIZE = LENGTH (HDR)
IF  BOUND>=DLSIZE THEN  START 
    !
    ! **** **** REPLACE THE FOLLOWING BY MACHINE CODE **** ****
    I = 1
    WHILE  I<=DLSIZE C 
    AND  BYTE INTEGER(A+I-1)=BYTE INTEGER(ADDR(HDR)+I) C 
    CYCLE 
        I = I + 1
    REPEAT 
    ! **** **** END OF MACHINE CODE SECTION **** ****
    !
    IF  I>DLSIZE THEN  START 
        ! WE HAVE MATCHED THE WHOLE OF THE HEADER IN THE DATA.
        ! PREPARE TO EXAMINE BYTES OF DATA BEYOND HEADER.
        I = A + DLSIZE
        IF  BOUND>DLSIZE THEN  START 
            ! IF THERE ARE ANY SUCH BYTES.
            !
            ! **** **** REPLACE BY MACHINE CODE: **** ****
            UNTIL  I=A+BOUND OR  C#' ' CYCLE 
                C = BYTE INTEGER (I)
                I = I + 1
            REPEAT 
            ! **** **** END OF MACHINE CODE SECTION **** ****
            !
        FINISH  ELSE  START ; ! BOUND=DLSIZE, SO I ALREADY =A+BOUND.
            C = NL
        FINISH 
        UNLESS  NL#C#' ' THEN  START 
            L = I - A
            SSOWN_ACCUMULATION_BOUND = SSOWN_ACCUMULATION_BOUND - L
            SSOWN_ACCUMULATION_ADDRESS = A + L
        FINISH 
    FINISH 
FINISH 
END 
!
SYSTEM  ROUTINE  SUPPLY DATA DESCRIPTOR (RECORD (PD) NAME  DR)
PROMPT ("Data:")
SSOWN_LAST PROMPT = -1
GATHER DATA (SSOWN_D DELIM 2, 3)
IF  SSOWN_ACCUMULATION_ADDRESS#0 THEN  DISCARD DATA HEADER (SSOWN_D DELIM 1)
DR = SSOWN_ACCUMULATION
END 
!
!
! MAXPCT IS THE MAXIMUM NUMBER OF PARAMETERS ALLOWED FOR ONE
! MACRO, AND MAXKNL IS THE MAXIMUM ALLOWED LENGTH FOR
! KEYWORDS.
CONST  INTEGER  MAXPCT = 24, MAXKNL = 11
!
!
!
! BRACKET FLAG=0 MEANS 'NO BRACKETS',
!             #0 MEANS 'BRACKETS'.
! %EXTERNAL %INTEGER BRACKET FLAG = 0
!
!
!
STRING  (255) FN  PURGE (STRING  NAME  D, F, INTEGER  NAME  L)
! THIS FUNCTION STARTS AT THE BEGINNING OF STRING 'D', AND (ASSUMING
! 'F' IS THE CORRESPONDING FLAGS STRING) DISCARDS ALL SPACES AND
! ACCUMULATES ALL OTHER CHARACTERS.  IT WILL, HOWEVER, NEVER
! ACCUMULATE ANY CHARACTERS IN QUOTES OR IN BRACKETS, NOR THE
! ENCLOSING QUOTES OR BRACKETS.  IT STOPS AS SOON AS IT FINDS THE FIRST
! SUCH CHARACTER, LEAVING THE 'DISPLACEMENT-WITHIN-STRING' OF THAT
! CHARACTER IN 'L'.  IF IT FINDS NO SUCH CHARACTER, 'L' WILL BE EQUAL
! TO LENGTH(D)+1.
STRING  (255) Q
INTEGER  I, S, P
L = LENGTH (D) + 1
I = 1
P = 0
WHILE  I<L CYCLE 
    S = BYTE INTEGER (ADDR(F)+I)
    IF  S#'A' THEN  START 
        IF  S='C' THEN  START 
            P = P + 1
            BYTE INTEGER (ADDR(Q)+P) = BYTE INTEGER (ADDR(D)+I)
        FINISH  ELSE  L = I
    FINISH 
    I = I + 1
REPEAT 
LENGTH (Q) = P
! L IS THE "ADDRESS" IN THE STRING OF THE FIRST CHARACTER NOT ACCEPTED.
IF  DIAGOP#0 THEN  START 
   PRINT STRING ("++++ Purging: """.D.""" yields """.Q."""")
   IF  L<=LENGTH(D) THEN  START 
       PRINT STRING (" with residue """.SUBSTRING(D,L,LENGTH(D))."""")
   FINISH 
   NEWLINE
   PRINT STRING ("               ".F)
   NEWLINE
FINISH 
RESULT  = Q
END 
!
ROUTINE  FIND FIELD (STRING  NAME  FLAG STRING, C 
    INTEGER  S, C 
    INTEGER  NAME  F, L, E)
! THIS ROUTINE SCANS THE STRING 'FLAG STRING' TO FIND
! A FIELD OF CONSECUTIVE 'C' SYMBOLS.  IT STARTS AT A
! SPECIFIED POSITION IN THE STRING, AND RETURNS INTEGERS
! SPECIFYING THE POSITION OF THE FIELD IF ONE IS FOUND.
!
! S IS THE 'SEARCH START POSITION' IN THE STRING.
! E IS THE 'EXISTENCE FLAG', NON-ZERO ON EXIT IFF
!    A FIELD WAS FOUND.
! F IS THE 'FIELD START POSITION' IN THE STRING.
! L IS THE 'FIRST POSITION BEYOND END OF STRING'.  THE FIELD
!    WILL BE IN POSITIONS F TO L-1, AND THE NEXT SEARCH SHOULD
!    START IN POSITION L+1.
! F AND L WILL NOT BE ASSIGNED IF E IS ZERO ON EXIT (I.E., NO
!    FIELD FOUND).
!
    INTEGER  SEARCH LIM
    SEARCH LIM = LENGTH (FLAG STRING)
    !
    ! **** **** THIS COULD BE REPLACED BY MACHINE CODE **** ****
    WHILE  S<=SEARCH LIM C 
    AND  BYTE INTEGER(ADDR(FLAG STRING)+S)#'C' C 
    CYCLE 
        S = S + 1
    REPEAT 
    ! **** **** END OF MACHINE CODE SECTION **** ****
    !
    IF  S>SEARCH LIM C 
    THEN  E = 0 C 
    ELSE  START 
        E = -1
        F = S
        !
        ! **** **** THIS COULD BE REPLACED BY MACHINE CODE **** ****
        UNTIL  S>SEARCH LIM C 
        OR  BYTE INTEGER(ADDR(FLAG STRING)+S)#'C' C 
        CYCLE 
            S = S + 1
        REPEAT 
        ! **** **** END OF MACHINE CODE SECTION **** ****
        !
        L = S
    FINISH 
END 
!
IF  ULCEQUIV=0 THEN  START 
   INTEGER  FN  RECOGNISE KWD (STRING  NAME  P)
   !
   ! IF YOU OFFER THIS FUNCTION A STRING, IT WILL RETURN ZERO IF
   ! IT CANNOT RECOGNISE THE STRING, OR
   !   1 FOR ".GOTO",
   !   2 FOR ".IF",
   !   3 FOR ".THEN",
   !   4 FOR ".ELSE",
   !   5 FOR ".START",
   !   6 FOR ".FINISH",
   !   7 FOR ".WHENEVER"
   !
       CONST  STRING  (10) ARRAY  KEYS (1:KWDS) = ".GOTO",
           ".IF",
           ".THEN",
           ".ELSE",
           ".START",
           ".FINISH",
           ".WHENEVER"
       INTEGER  I
       FOR  I=1,1,KWDS CYCLE 
           IF  P=KEYS(I) THEN  RESULT  = I
       REPEAT 
       RESULT  = 0
   END 
FINISH  ELSE  START 
   INTEGER  FN  RECOGNISE KWD (STRING  (80) P)
   !
   ! IF YOU OFFER THIS FUNCTION A STRING, IT WILL RETURN ZERO IF
   ! IT CANNOT RECOGNISE THE STRING, OR
   !   1 FOR ".GOTO",
   !   2 FOR ".IF",
   !   3 FOR ".THEN",
   !   4 FOR ".ELSE",
   !   5 FOR ".START",
   !   6 FOR ".FINISH",
   !   7 FOR ".WHENEVER"
   !
       CONST  STRING  (10) ARRAY  KEYS (1:KWDS) = ".GOTO",
           ".IF",
           ".THEN",
           ".ELSE",
           ".START",
           ".FINISH",
           ".WHENEVER"
       INTEGER  I
       UCTRANSLATE (ADDR(P)+1,LENGTH(P))
       FOR  I=1,1,KWDS CYCLE 
           IF  P=KEYS(I) THEN  RESULT  = I
       REPEAT 
       RESULT  = 0
END 
FINISH 
!
!
! %ROUTINE LINE IN (%STRING %NAME TEXT, %INTEGER %NAME R)
! !
! ! THIS READS A LINE OF TEXT INTO %STRING 'TEXT', USING 'MASTER CHAR IN'.
! ! TRAILING SPACES AND THE FINAL 'NEWLINE' CHARACTER ARE NOT INCLUDED IN
! ! THE TEXT RETURNED TO THE CALLER.  RESULTS ARE:
! !   0 - O.K.
! !   3 - END OF FILE FOUND
! !   4 - LINE TOO LONG
! !
! ! THE DECLARED MAXIMUM LENGTH OF 'TEXT' MUST BE 255.
! !
! %INTEGER INDEX, SPACES, C
! R = 0
! !
! ! **** **** REPLACE BY MACHINE CODE **** ****
! %FOR INDEX = 1,1,255 %CYCLE
!     BYTE INTEGER (ADDR(TEXT)+INDEX) = ' '
! %REPEAT
! ! **** **** END OF MACHINE CODE SECTION **** ****
! !
! SPACES = 0
! INDEX = 0
! %UNTIL C=NL %CYCLE
!     C = MASTER CHAR IN (1)
!     %IF C=25 %THEN %START
!         C = NL
!         R = 3
!     %FINISH
!     %IF C#NL %THEN %START
!         %IF C=' ' %C
!         %THEN SPACES = SPACES + 1 %C
!         %ELSE %START
!             INDEX = INDEX + SPACES + 1
!             SPACES = 0
!             %IF INDEX<=255 %C
!             %THEN BYTE INTEGER (ADDR(TEXT)+INDEX) = C %C
!             %ELSE %START
!                 INDEX = 255
!                 R = 4
!             %FINISH
!         %FINISH
!     %FINISH
! %REPEAT
! LENGTH (TEXT) = INDEX
! !
! %END
!
!
!
!
! %ROUTINE TIDY LINE (%STRING %NAME RAW, RECON, MARKS, %C
!     %INTEGER %NAME STATE, BL, %INTEGER QC)
! !
! ! THIS ROUTINE DOES MULTIPLE SPACE REDUCTION, BRACKET COUNTING,
! ! ELIMINATION OF COMMENTS, AND RECOGNITION OF TEXT IN QUOTES.
! ! THE ORIGINAL TEXT IN 'RAW' SHOULD CONTAIN NO NEWLINE CHARACTER.
! ! RECONSTRUCTED TEXT WILL BE APPENDED TO 'RECON', AND FLAG BYTES
! ! PUT IN THE CORRESPONDING POSITIONS IN 'MARKS'.  IT IS THE
! ! CALLER'S RESPONSIBILITY TO INITIALISE 'RECON' WITH A NULL STRING
! ! BEFORE CALLING 'TIDY LINE' IF NECESSARY.  HE HAS ALSO TO
! ! CLEAR 'BL' (BRACKET LEVEL) TO ZERO AND INITIALISE 'STATE' TO 1.
! ! ON EXIT, 'STATE' WILL BE 2 NORMALLY, OR 3 IF THE END OF THE INPUT
! ! LINE WAS REACHED 'IN QUOTES'.  IF THE TEXT HAS OVERFLOWED 'RECON',
! ! THEN 'STATE' WILL BE 255.  'BL' WILL GIVE THE DEPTH OF BRACKETING
! ! REMAINING AT THE END OF LINE.  'QC' CONTROLS WHETHER TWO CONSECUTIVE
! ! QUOTE MARKS WITHIN QUOTES WILL BE REDUCED TO A SINGLE QUOTE (QC#0), OR
! ! NOT REDUCED (QC=0).  IF IT IS CERTAIN THAT 'QC' WILL ALWAYS BE ZERO,
! ! THEN STATE 5 BECOMES REDUNDANT IN THE CODE BELOW.
! ! THE DECLARED MAXIMUM LENGTH OF 'RECON' AND 'MARKS' MUST BE 255.
! ! THE FLAG BYTES PUT INTO 'MARKS' ARE DESCRIBED IN THE COMMENT FOR
! ! 'GET STMT'.
! %CONST %BYTE %INTEGER %ARRAY MARKER (1:5,0:5) = %C
!     'E', 'E', 'E', ' ', 'E',
!     ' ', 'A', 'E', ' ', 'A',
!     ' ', 'A', 'E', ' ', 'A',
!     'C', 'C', 'E', ' ', 'C',
!     'C', 'C', 'E', ' ', 'C',
!     'C', 'C', 'E', ' ', 'C',
! %CONST %BYTE %INTEGER %ARRAY NEXT STATE (1:5,0:5) = %C
!     3, 3, 5, 4, 3,
!     4, 4, 3, 1, 4,
!     1, 1, 3, 4, 1,
!     2, 2, 3, 4, 2,
!     2, 2, 3, 4, 2,
!     2, 2, 3, 4, 2,
! %CONST %BYTE %INTEGER %ARRAY ACTIONS (1:5,0:5) = %C
!     0, 0, 0, 0, 3,
!     0, 0, 0, 0, 0,
!     0, 0, 0, 0, 0,
!     1, 1, 0, 0, 1,
!     2, 2, 0, 0, 2,
!     0, 0, 0, 0, 0,
! %SWITCH PROCESS (0:3)
! %INTEGER C, D, CSW, L, I, LR
! %STRING (4) RESIDUE
! I = 1
! L = LENGTH (RECON)
! LR = LENGTH (RAW) + 1
! %WHILE I<LR %CYCLE
!     C = BYTE INTEGER (ADDR(RAW)+I)
!     !
!     ! **** **** REPLACE BY MACHINE CODE **** ****
!     %IF SSOWN_SPECHARS->RESIDUE.(TOSTRING(C)) %C
!     %THEN CSW = LENGTH (RESIDUE) %C
!     %ELSE CSW = 5
!     ! **** **** END OF MACHINE CODE SECTION **** ****
!     !
!     ! CSW WILL BE -
!     !   0 FOR DOUBLE-QUOTE,
!     !   1 FOR COMMENT SYMBOL,
!     !   2 FOR A SPACE,
!     !   3 FOR OPEN BRACKET,
!     !   4 FOR CLOSE BRACKET,
!     !   5 FOR ANYTHING ELSE.
!     !
!     ! VALUES OF 'STATE' ARE -
!     !   1 : START-OF-LINE OR AFTER A SPACE,
!     !   2 : NORMAL,
!     !   3 : IN QUOTES,
!     !   4 : IN COMMENT,
!     !   5 : AFTER A CLOSING QUOTE.
!     !
!     D = MARKER (STATE, CSW)
!     -> PROCESS (ACTIONS(STATE,CSW))
!     !
! PROCESS (1):
!     BL = BL + 1
!     -> PLANT
!     !
! PROCESS (2):
!     %IF BL>0 %THEN %START
!         BL = BL - 1
!         %IF BL=0 %THEN D = 'D'
!     %FINISH
!     -> PLANT
!     !
! PROCESS (3):
!     %IF QC#0 %THEN D='D'
!     ! -> PLANT
!     !
! PROCESS (0):
! PLANT:
!     STATE = NEXT STATE (STATE, CSW)
!     %IF D#' ' %THEN %START
!         %IF D='A' %THEN C = ' '
!         %IF BL>0 %THEN D = D + 1
!         %IF L>=255 %THEN %START
!             STATE = 255
!             I = LR; ! ENSURES EXIT FROM THE LOOP.
!         %FINISH %ELSE %START
!             L = L + 1
!             BYTE INTEGER (ADDR(RECON)+L) = C
!             BYTE INTEGER (ADDR(MARKS)+L) = D
!         %FINISH
!     %FINISH
!     I = I + 1
! %REPEAT
! %IF STATE=1 %AND L>0 %THEN L = L - 1
! %IF 255#STATE#3 %THEN STATE = 2
! LENGTH (RECON) <- L
! LENGTH (MARKS) <- L
! !
! %END
!
!
ROUTINE  GET STMT C 
   (INTEGER  BRACKET OPTION, C 
    INTEGER  QUOTE CONTRACTION, C 
    INTEGER  COMM, C 
    STRING  (80) D DELIM 1, C 
    STRING  (80) CONT, C 
    STRING  (80) CANCEL, C 
    STRING  NAME  INPUT, C 
    STRING  NAME  RECON, C 
    STRING  NAME  MARKS, C 
    INTEGER  NAME  F)
!
! THIS ROUTINE READS A COMPLETE STATEMENT VIA 'MASTER CHAR IN'
! (I.E., THROUGH THE MACRO EXPANSION PROCESS WHEN APPROPRIATE).
! THE UNPROCESSED TEXT WILL BE COPIED INTO THE STRING 'INPUT'.
! THE LAST CHARACTER READ WILL ALWAYS BE A NEWLINE (OR END-OF-FILE)
! UNLESS THE TEXT OVERFLOWS 'INPUT', IN WHICH CASE READING STOPS
! AT THAT POINT.
! THE TEXT AFTER RECONSTRUCTION IS PUT INTO 'RECON'.  RECONSTRUCTION
! MEANS THAT -
! EACH COMMENT IS REPLACED BY A SINGLE SPACE.
! QUOTES ARE PROPERLY MATCHED, SO THAT A NEWLINE IN QUOTES DOES NOT
! TERMINATE A STATEMENT.  NO LINE RECONSTRUCTION IS APPLIED TO TEXT
! IN QUOTES (EXCEPT TRAILING SPACE DELETION).
! IF THE 'BRACKETS' OPTION IS USED, BRACKETS ARE PROPERLY MATCHED, AND
! A NEWLINE WITHIN BRACKETS DOES NOT TERMINATE THE STATEMENT.  IT IS
! REPLACED BY A SINGLE SPACE, AND THE TEXT FROM THE NEXT LINE IS
! PROCESSED AS PART OF THE STATEMENT.
! WHERE A LINE ENDS WITH THE CONTINUATION MARKER, ALL CHARACTERS FROM
! THE MARKER TO THE NEWLINE ARE REPLACED BY A SINGLE SPACE, AND
! THE TEXT FROM THE NEXT LINE IS PROCESSED AS PART OF THE STATEMENT.
! THE TERMINATING NEWLINE OR END-OF-FILE CHARACTER WILL HAVE BEEN
! REMOVED, AND THE TEXT WILL HAVE NO LEADING OR TRAILING SPACES.
! ALL MULTIPLE SPACES, EXCEPT IN QUOTES, ARE REPLACED BY SINGLE SPACES.
!
! BRACKET OPTION=0 MEANS 'ASSUME NOBRACKETS'
!               #0 MEANS 'ASSUME BRACKETS OPTION'.
! QUOTE CONTRACTION#0 MEANS 'REDUCE "" TO " IF ALREADY IN QUOTES'
!                  =0 MEANS DON'T.
! COMM IS THE (SINGLE BYTE) COMMENT SYMBOL.
! D DELIM 1 IS THE OPENING DATA DELIMITER.
! CONT IS THE CONTINUATION MARKER.
! RAW TEXT WILL BE PUT INTO 'INPUT'.
! TEXT AFTER LINE RECONSTRUCTION WILL BE PUT INTO 'RECON'.
! CORRESPONDING TO EACH BYTE IN 'RECON' WILL BE ONE BYTE IN THE SAME
! POSITION IN 'MARKS'.
! 'MARKS' WILL GET:
!                     IN PLAIN TEXT       IN BRACKETS
! SPACE OR NEWLINE         A                   B
! TEXT                     C                   D
! TEXT IN QUOTES           E                   F
!
! THE OUTER BRACKETS (AND OF COURSE INNER BRACKETS ALSO)
! IN A SEQUENCE OF TEXT-IN-BRACKETS GET THE FLAG 'D'.
! THE OUTER QUOTES IN A SEQUENCE OF TEXT-IN-QUOTES GET THE
! FLAG 'E', OR 'F' IF IN BRACKETS.
!
! THE MAXIMUM LENGTH OF THE STRINGS INPUT, RECON AND MARKS MUST BE 255.
!
! 'F' WILL GET A VALUE TO INDICATE THE SUCCESS OR FAILURE OF
! GET STMT, AS FOLLOWS:
! F = 0: O.K.
! F = 1: OPENING DATA DELIMITER FOUND.
! F = 2: INCOMPLETE STATEMENT BEFORE DATA DELIMITER.
! F = 3: INCOMPLETE STATEMENT BEFORE END OF FILE.
! F = 4: STATEMENT TOO LONG.
! F = -1: PARAMETERS UNACCEPTABLE.
!
CONST  BYTE  INTEGER  ARRAY  MARKER (1:5,0:5) = C 
    'E', 'E', 'E', ' ', 'E',
    ' ', 'A', 'E', ' ', 'A',
    ' ', 'A', 'E', ' ', 'A',
    'C', 'C', 'E', ' ', 'C',
    'C', 'C', 'E', ' ', 'C',
    'C', 'C', 'E', ' ', 'C'
CONST  BYTE  INTEGER  ARRAY  NEXT STATE (1:5,0:5) = C 
    3, 3, 5, 4, 3,
    4, 4, 3, 1, 4,
    1, 1, 3, 4, 1,
    2, 2, 3, 4, 2,
    2, 2, 3, 4, 2,
    2, 2, 3, 4, 2
CONST  BYTE  INTEGER  ARRAY  ACTIONS (1:5,0:5) = C 
    0, 0, 0, 0, 3,
    0, 0, 0, 0, 0,
    0, 0, 0, 0, 0,
    1, 1, 0, 0, 1,
    2, 2, 0, 0, 2,
    0, 0, 0, 0, 0
SWITCH  PROCESS (0:3)
INTEGER  D, CSW, L, I
STRING  (4) RESIDUE
INTEGER  LC, LR, LS, BL, IC, BM, STATE, PARMS OK
INTEGER  INDEX, SPACES, C
!
! CHECK PARAMETERS:
PARMS OK = -1; ! TRUE.
LC = LENGTH (CONT)
BEGIN 
    STRING  (255) C1, C2
    IF  CONT="" C 
    OR  D DELIM 1="" C 
    OR  COMM=' ' C 
    OR  COMM='"' C 
    OR  CONT->C1.(TOSTRING(COMM)).C2 C 
    OR  CONT->C1.(" ").C2 C 
    OR  CONT->C1.("""").C2 C 
    OR  D DELIM 1->C1.(TOSTRING(COMM)).C2 C 
    OR  D DELIM 1->C1.(" ").C2 C 
    OR  D DELIM 1->C1.("""").C2 C 
    OR  D DELIM 1->C1.(CONT).C2 C 
    OR  CONT->C1.(D DELIM 1).C2 C 
    OR  LENGTH(CANCEL)#LC C 
    THEN  PARMS OK = 0; ! FALSE.
END 
IF  PARMS OK=0 THEN  START 
    F = -1
    RETURN 
FINISH 
!
!
STATE = 1
BL = 0
RECON = ""
MARKS = ""
UNTIL  F#5 CYCLE 
!   LINE IN (INPUT, F)
! <<<<
!
! THIS READS A LINE OF TEXT INTO %STRING 'INPUT', USING 'MASTER CHAR IN'.
! TRAILING SPACES AND THE FINAL 'NEWLINE' CHARACTER ARE NOT INCLUDED IN
! THE TEXT RETURNED TO THE CALLER.  RESULTS ARE:
!   0 - O.K.
!   3 - END OF FILE FOUND
!   4 - LINE TOO LONG
!
! THE DECLARED MAXIMUM LENGTH OF 'INPUT' MUST BE 255.
!
F = 0
!
! **** **** REPLACE BY MACHINE CODE **** ****
FOR  INDEX = 1,1,255 CYCLE 
    BYTE INTEGER (ADDR(INPUT)+INDEX) = ' '
REPEAT 
! **** **** END OF MACHINE CODE SECTION **** ****
!
SPACES = 0
INDEX = 0
UNTIL  C=NL CYCLE 
    C = MASTER CHAR IN (1)
    IF  C=25 THEN  START 
        C = NL
        F = 3
    FINISH 
    IF  C#NL THEN  START 
        IF  C=' ' C 
        THEN  SPACES = SPACES + 1 C 
        ELSE  START 
            INDEX = INDEX + SPACES + 1
            SPACES = 0
            IF  INDEX<=255 C 
            THEN  BYTE INTEGER (ADDR(INPUT)+INDEX) = C C 
            ELSE  START 
                INDEX = 255
                F = 4
            FINISH 
        FINISH 
    FINISH 
REPEAT 
LENGTH (INPUT) = INDEX
!
! >>>>
    IF  F=0 THEN  START 
        IF  INPUT=D DELIM 1 C 
        THEN  F = 1 C 
        ELSE  START 
!           TIDY LINE (INPUT,RECON,MARKS,STATE,BL,QUOTE CONTRACTION)
! <<<< <<<< <<<<
!
! THIS ROUTINE DOES MULTIPLE SPACE REDUCTION, BRACKET COUNTING,
! ELIMINATION OF COMMENTS, AND RECOGNITION OF TEXT IN QUOTES.
! THE ORIGINAL TEXT IN 'INPUT' SHOULD CONTAIN NO NEWLINE CHARACTER.
! RECONSTRUCTED TEXT WILL BE APPENDED TO 'RECON', AND FLAG BYTES
! PUT IN THE CORRESPONDING POSITIONS IN 'MARKS'.  IT IS THE
! CALLER'S RESPONSIBILITY TO INITIALISE 'RECON' WITH A NULL STRING
! BEFORE CALLING 'TIDY LINE' IF NECESSARY.  HE HAS ALSO TO
! CLEAR 'BL' (BRACKET LEVEL) TO ZERO AND INITIALISE 'STATE' TO 1.
! ON EXIT, 'STATE' WILL BE 2 NORMALLY, OR 3 IF THE END OF THE INPUT
! LINE WAS REACHED 'IN QUOTES'.  IF THE TEXT HAS OVERFLOWED 'RECON',
! THEN 'STATE' WILL BE 255.  'BL' WILL GIVE THE DEPTH OF BRACKETING
! REMAINING AT THE END OF LINE.  'QUOTE CONTRACTION' CONTROLS WHETHER
! TWO CONSECUTIVE QUOTE MARKS WITHIN QUOTES WILL BE REDUCED TO A SINGLE
! QUOTE (QUOTE CONTRACTION#0), OR NOT REDUCED (QUOTE CONTRACTION=0).
! IF IT IS CERTAIN THAT 'QUOTE CONTRACTION' WILL ALWAYS BE ZERO,
! THEN STATE 5 BECOMES REDUNDANT IN THE CODE BELOW.
! THE DECLARED MAXIMUM LENGTH OF 'RECON' AND 'MARKS' MUST BE 255.
! THE FLAG BYTES PUT INTO 'MARKS' ARE DESCRIBED IN THE COMMENT FOR
! 'GET STMT'.
I = 1
L = LENGTH (RECON)
LR = LENGTH (INPUT) + 1
WHILE  I<LR CYCLE 
    C = BYTE INTEGER (ADDR(INPUT)+I)
    !
    ! **** **** REPLACE BY MACHINE CODE **** ****
    IF  SSOWN_SPECHARS->RESIDUE.(TOSTRING(C)) C 
    THEN  CSW = LENGTH (RESIDUE) C 
    ELSE  CSW = 5
    ! **** **** END OF MACHINE CODE SECTION **** ****
    !
    ! CSW WILL BE -
    !   0 FOR DOUBLE-QUOTE,
    !   1 FOR COMMENT SYMBOL,
    !   2 FOR A SPACE,
    !   3 FOR OPEN BRACKET,
    !   4 FOR CLOSE BRACKET,
    !   5 FOR ANYTHING ELSE.
    !
    ! VALUES OF 'STATE' ARE -
    !   1 : START-OF-LINE OR AFTER A SPACE,
    !   2 : NORMAL,
    !   3 : IN QUOTES,
    !   4 : IN COMMENT,
    !   5 : AFTER A CLOSING QUOTE.
    !
    D = MARKER (STATE, CSW)
    -> PROCESS (ACTIONS(STATE,CSW))
    !
PROCESS (1):
    BL = BL + 1
    -> PLANT
    !
PROCESS (2):
    IF  BL>0 THEN  START 
        BL = BL - 1
        IF  BL=0 THEN  D = 'D'
    FINISH 
    -> PLANT
    !
PROCESS (3):
    IF  QUOTE CONTRACTION#0 THEN  D='D'
    ! -> PLANT
    !
PROCESS (0):
PLANT:
    STATE = NEXT STATE (STATE, CSW)
    IF  D#' ' THEN  START 
        IF  D='A' THEN  C = ' '
        IF  BL>0 THEN  D = D + 1
        IF  L>=255 THEN  START 
            STATE = 255
            I = LR; ! ENSURES EXIT FROM THE LOOP.
        FINISH  ELSE  START 
            L = L + 1
            BYTE INTEGER (ADDR(RECON)+L) = C
            BYTE INTEGER (ADDR(MARKS)+L) = D
        FINISH 
    FINISH 
    I = I + 1
REPEAT 
IF  STATE=1 AND  L>0 THEN  L = L - 1
IF  255#STATE#3 THEN  STATE = 2
LENGTH (RECON) <- L
LENGTH (MARKS) <- L
!
! >>>> >>>> >>>>
            LR = LENGTH (RECON)
            LS = LR
            IC = ' '; ! CHARACTER TO INSERT IF WE NEED TO TAG ANOTHER
                      ! LINE ONTO THIS ONE.
            BM = 'A'; ! MARKER TO INSERT.
            IF  STATE=3 THEN  START ; ! IN QUOTES.
                IF  LR<255 THEN  START 
                    IC = NL
                    BM = 'E'
                    LS = LR + 1
                FINISH  ELSE  STATE = 255
            FINISH  ELSE  START 
                IF  STATE=2 THEN  START 
                    LS = LR - LC
                    IF  LS>=0 THEN  START 
                        IF  SUBSTRING (RECON,LS+1,LR)=CONT C 
                        THEN  START 
                            LR = LS
                            STATE = 1
                            IF  LS#0 C 
                            AND  BYTE INTEGER(ADDR(RECON)+LS)#' ' C 
                            THEN  LS = LS + 1
                        FINISH  ELSE  START 
                            IF  SUBSTRING (RECON,LS+1,LR)=CANCEL C 
                            THEN  START 
                                STATE = 1
                                BL = 0
                                LS = 0
                            FINISH  ELSE  START 
                                IF  BL>0 AND  BRACKET OPTION#0 C 
                                THEN  START 
                                    IF  LR<255 THEN  START 
                                        LS = LR + 1
                                        STATE = 1
                                    FINISH  ELSE  STATE = 255
                                FINISH 
                            FINISH 
                        FINISH 
                    FINISH 
                FINISH 
            FINISH 
            IF  STATE=2 THEN  F = 0 ELSE  START 
                IF  STATE=255 THEN  F = 4 ELSE  START 
                    F = 5
                    IF  LS>LR THEN  START 
                        IF  BL#0 THEN  BM = BM + 1
                        BYTE INTEGER (ADDR(RECON)+LS) = IC
                        BYTE INTEGER (ADDR(MARKS)+LS) = BM
                    FINISH 
                    LENGTH (RECON) = LS
                    LENGTH (MARKS) = LS
                FINISH 
            FINISH 
        FINISH 
    FINISH 
REPEAT 
IF  F=1 AND  RECON#"" THEN  F = 2
RETURN 
!
END 
!
!
!
!
INTEGER  FN  CLASSIFY STMT C 
   (STRING  NAME  STMT, FLAGS, LABEL STRING, C 
    PREDICATE STRING, CALL STRING, DEST STRING, PF, CF, DF)
!
! IF YOU OFFER THIS FUNCTION A LINE OF TEXT, IT WILL RETURN:
!   5 FOR  "SIMPLE CALL" (OR ANYTHING NOT EXPLICITLY RECOGNISED
!                         AS ONE OF THE OTHER FORMS),
!   6 FOR  ".GOTO",
!   7 FOR  ".IF .GOTO",
!   8 FOR  ".IF .THEN",
!   9 FOR  ".IF .START",
!   10 FOR ".ELSE",
!   11 FOR ".FINISH",
!   12 FOR ".WHENEVER .GOTO",
!   13 FOR ".WHENEVER .THEN",
!   14 FOR ".WHENEVER .START"
! IT ASSUMES THAT 'STMT' HAS BEEN SUCCESSFULLY READ AND RECONSTRUCTED
! BY 'GET STMT' - E.G., 'STMT' MUST CONTAIN NO NEWLINES OR MULTIPLE
! SPACES - AND THAT 'FLAGS' IS THE CORRESPONDING FLAG STRING.  'GET
! STMT' SHOULD HAVE RETURNED A ZERO RESULT ON READING THE LINE.  ON
! EXIT, 'LABEL STRING' WILL HAVE ANY LABEL FOUND ON THE LINE, OR
! A NULL STRING IF THE LINE WAS UNLABELLED.  IF THE FORM OF THE LINE
! INCLUDES A PREDICATE, THEN THE TEXT OF THE PREDICATE WILL BE COPIED
! INTO 'PRED STRING', AND 'PF' WILL GET THE CORRESPONDING FLAG STRING.
! SIMILARLY 'CALL STRING' AND 'CF' WILL BE USED FOR ANY CALL, AND
! 'DEST STRING' AND 'DF' FOR THE DESTINATION OF ANY '.GOTO'.  THESE
! STRINGS MAY BE NULL IF THE FORM OF LINE INCLUDES THE APPROPRIATE PART
! BUT THE ACTUAL LINE HAD NO TEXT IN THE RELEVANT PLACE.  IF THE PART IS
! NOT REQUIRED IN THE FORM OF THE LINE, THEN THE RELEVANT STRINGS MAY
! NOT BE ASSIGNED AT ALL.
!
STRING  (255) FLD
INTEGER  DT, KT, FIELD FOUND, FIELD START, FIELD END
INTEGER  PRED START, SEARCH START, CPTR
SWITCH  PKWD (0:KWDS); ! BOUNDS MUST COVER ALL VALUES WHICH CAN COME
! FROM 'RECOGNISE KWD'.
!
    LABEL STRING = ""
    PREDICATE STRING = "";     PF = ""
    CALL STRING = "";          CF = ""
    DEST STRING = "";          DF = ""
    IF  STMT="" THEN  RESULT  = 5
    FIELD FOUND = 0
    SEARCH START = 1
    UNTIL  FIELD FOUND#0 CYCLE 
        FIND FIELD (FLAGS, SEARCH START, C 
            FIELD START, FIELD END, FIELD FOUND)
        IF  FIELD FOUND=0 OR  FIELD START#SEARCH START THEN  START 
            CALL STRING = SUBSTRING (STMT, SEARCH START, LENGTH(STMT))
            CF = SUBSTRING (FLAGS, SEARCH START, LENGTH(FLAGS))
            RESULT  = 5
        FINISH 
        IF  SEARCH START=1 THEN  START 
            CPTR = 1
            !
            ! **** **** MACHINE CODE **** ****
            WHILE  CPTR<FIELD END C 
            AND  BYTE INTEGER(ADDR(STMT)+CPTR)#':' C 
            CYCLE 
                CPTR = CPTR + 1
            REPEAT 
            ! **** **** END OF MACHINE CODE **** ****
            !
            IF  CPTR<FIELD END THEN  START 
                FIELD FOUND = 0
                IF  CPTR>1 THEN  START 
                    LABEL STRING = SUBSTRING (STMT, 1, CPTR-1)
                    IF  ULCEQUIV#0 THEN  START 
                        UCTRANSLATE (ADDR(LABEL STRING)+1, CPTR-1)
                    FINISH 
                FINISH 
                IF  CPTR<LENGTH(FLAGS) C 
                AND  BYTE INTEGER(ADDR(FLAGS)+CPTR+1)='A' C 
                THEN  CPTR = CPTR + 1
                IF  CPTR>=LENGTH(STMT) THEN  RESULT  = 5
                SEARCH START = CPTR + 1
            FINISH 
        FINISH 
    REPEAT 
    FLD = SUBSTRING (STMT,FIELD START,FIELD END-1)
    CALL STRING = SUBSTRING (STMT,FIELD START,LENGTH(STMT))
    CF = SUBSTRING (FLAGS,FIELD START,LENGTH(FLAGS))
    IF  FIELD END<=LENGTH(STMT) THEN  START 
        DEST STRING = SUBSTRING (STMT,FIELD END,LENGTH(STMT))
        DF = SUBSTRING (FLAGS,FIELD END,LENGTH(FLAGS))
    FINISH ; ! %ELSE %START (BUT WE HAVE ALREADY DONE THIS):
    !   DEST STRING = ""
    !   DF = ""
    ! %FINISH
    KT = RECOGNISE KWD (FLD)
    -> PKWD (KT)
!
PKWD (0): ! NO KEYWORD RECOGNISED:
PKWD (3): ! .THEN:
PKWD (5): ! .START:
    RESULT  = 5; ! IGNORE THE KEYWORD - PROCESS STATEMENT AS A CALL.
!
PKWD (1): ! GOTO:
    IF  DEST STRING#"" THEN  RESULT  = 6
    RESULT  = 5
!
PKWD (4): ! ELSE:
    CALL STRING = DEST STRING
    CF = DF
    RESULT  = 10
!
PKWD (6): ! FINISH:
    IF  DEST STRING="" THEN  RESULT  = 11
    RESULT  = 5
!
PKWD (2): ! .IF:
PKWD (7): ! .WHENEVER:
    PRED START = FIELD END
    UNTIL  FIELD FOUND=0 CYCLE 
        FIND FIELD (FLAGS,FIELD END+1,FIELD START,FIELD END,FIELD FOUND)
        IF  FIELD FOUND#0 THEN  START 
            PREDICATE STRING = C 
                SUBSTRING (STMT,PRED START,FIELD START-1)
            PF = SUBSTRING (FLAGS,PRED START,FIELD START-1)
            FLD = SUBSTRING (STMT,FIELD START,FIELD END-1)
            IF  FIELD END<LENGTH(STMT) THEN  START 
                DEST STRING = C 
                    SUBSTRING (STMT,FIELD END,LENGTH(STMT))
                DF = SUBSTRING (FLAGS,FIELD END,LENGTH(FLAGS))
            FINISH  ELSE  START 
                DEST STRING = ""
                DF = ""
            FINISH 
            DT = RECOGNISE KWD (FLD)
            IF  DT=1 THEN  START ; ! .GOTO:
                IF  DEST STRING#"" THEN  RESULT  = 5 + KT
                ! 7 FOR .IF - .GOTO,
                ! 12 FOR .WHENEVER - .GOTO,
                ! IGNORE .GOTO WITH NO DESTINATION.
            FINISH 
            IF  DT=3 THEN  START ; ! .THEN:
                CALL STRING = DEST STRING
                CF = DF
                RESULT  = 6 + KT
                ! 8 FOR .IF - .THEN,
                ! 13 FOR .WHENEVER - .THEN
            FINISH 
            IF  DT=5 THEN  START 
                IF  DEST STRING="" THEN  RESULT  = 7 + KT
                ! 9 FOR .IF - .START,
                ! 14 FOR .WHENEVER - .START,
                ! IGNORE .START FOLLOWED BY FURTHER TEXT.
            FINISH 
        FINISH 
    REPEAT 
    RESULT  = 5
END 
!
!
ROUTINE  ANALYSE CALL N C 
    (STRING  NAME  CS, FS, R, P, INTEGER  NAME  W)
INTEGER  I, NS, NE, NF
R = ""
IF  LENGTH(FS)>0 THEN  START 
    ! SKIP OVER LEADING SPACES, IF ANY:
    ! (MULTIPLE SPACES CANNOT OCCUR).
    IF  BYTE INTEGER (ADDR(FS)+1)='A' THEN  I = 2 ELSE  I = 1
    IF  I<=LENGTH(FS) THEN  START 
        FIND FIELD (FS, I, NS, NE, NF)
        IF  NF#0 AND  NS=I THEN  START 
            R = SUBSTRING (CS, NS, NE-1)
            IF  ULCEQUIV#0 THEN  START 
               UCTRANSLATE (ADDR(R)+1, LENGTH(R))
            FINISH 
            IF  NE<=LENGTH(FS) THEN  START 
                IF  BYTE INTEGER(ADDR(FS)+NE)#'A' C 
                THEN  W = 16 C 
                ELSE  START 
                    IF  NE<LENGTH(FS) THEN  START 
                        IF  BYTE INTEGER(ADDR(FS)+LENGTH(FS)) C 
                            ='A' C 
                        THEN  P = SUBSTRING C 
                            (CS,NE+1,LENGTH(FS)-1) C 
                        ELSE  P = SUBSTRING C 
                            (CS,NE+1,LENGTH(FS))
                    FINISH 
                FINISH 
            FINISH 
        FINISH  ELSE  W = 16
    FINISH 
FINISH 
END 
!
ROUTINE  ANALYSE CALL B C 
    (STRING  NAME  CS, FS, R, P, INTEGER  NAME  W)
INTEGER  E, I, NS, NE
R = PURGE (CS, FS, NS)
IF  ULCEQUIV#0 THEN  START 
    UCTRANSLATE (ADDR(R)+1, LENGTH(R))
FINISH 
IF  NS<=LENGTH(CS) THEN  START 
    IF  R="" THEN  W = 16 ELSE  START 
        I = NS
        NE = LENGTH (CS) + 1
        UNTIL  I>=NE CYCLE 
            E = BYTE INTEGER (ADDR(FS)+I)
            IF  E#'B' AND  E#'D' AND  E#'F' THEN  NE = I
            I = I + 1
        REPEAT 
        IF  NE<=LENGTH(CS) THEN  START 
            UNLESS  NE=LENGTH(CS) C 
            AND  BYTE INTEGER(ADDR(FS)+NE)='A' C 
            THEN  W = 16
        FINISH 
        IF  W=0 AND  NS<NE-2 C 
        THEN  P = SUBSTRING (CS, NS+1, NE-2)
    FINISH 
FINISH 
END 
!
!
!
!
SYSTEM  ROUTINE  INIT CLI VARS
! %OWN %INTEGER CLI INITIALISED = 0
IF  SSOWN_CLI INITIALISED=0 THEN  START 
    SSOWN_COMMENTF = '@'
    SSOWN_SPECHARS = """  ()"
    BYTE INTEGER (ADDR(SSOWN_SPECHARS)+2) = SSOWN_COMMENTF
    SSOWN_D DELIM 1 = DATA START MARK
    SSOWN_D DELIM 2 = DATA END MARK
    SSOWN_CONTU = ".C"
    SSOWN_XSTMT = ".A"
    SSOWN_CLI INITIALISED = -1
FINISH 
END 
!
!
SYSTEM  ROUTINE  EXAMINE MACRO (STRING  NAME  MAC NAME, CALL PARMS, C 
    INTEGER  TEXT BOUND, TEXT ADDRESS, SET UP, C 
    INTEGER  NAME  FAIL FLAG)
!
! IF 'SET UP' IS NON-ZERO, THIS ROUTINE DOES THE 'SET UP MACRO' PROCESS.
! IF IT IS ZERO, IT SIMPLY DOES 'RECOGNISE MACRO'.
!
! POSSIBLE VALUES OF 'FAIL FLAG' ON EXIT:
! FOR 'SET UP MACRO' -
!   0 - SUCCESS
!   X'80000001' - KEYWORD MISSING IN DECLARATION
!   X'80000004' - TOO MANY FIELDS IN DECLARATION
!   X'80000080' - KEYWORDS INDISTINCT IN HEADER
!   X'80000400' - TOO LITTLE SPACE IN MACRO EXPANSION AREA
!   X'80000800' - CANNOT RECOGNISE MACRO HEADER
!   X'80001000' - TOO MANY INPUT LEVELS
! FOR 'RECOGNISE MACRO' -
!   0 - SUCCESS
!   X'80000800' - CANNOT RECOGNISE MACRO HEADER
!   X'80001000' - TOO MANY INPUT LEVELS
! THE MAXIMUM LENGTH OF THE STRINGS IN KNTXT MUST BE MAXKNL:
STRING  (11) ARRAY  KNTXT (1:MAXPCT)
RECORD (PD) ARRAY  PVAL (1:MAXPCT)
INTEGER  PCT, R, BMARK
STRING  (255) RN, PS, ST, FG, LBLSTR, PREDSTR,  CALLSTR, DESTR
STRING  (255) PFSTR, CFSTR, DFSTR, RAW
!
!
ROUTINE  GET AND CLASSIFY (INTEGER  BRACKETS)
GET STMT (BRACKETS,0,SSOWN_COMMENTF,SSOWN_D DELIM 1,SSOWN_CONTU,SSOWN_XSTMT,RAW,ST,FG,R)
IF  DIAGOP#0 THEN  START 
   IF  R#0 THEN  START 
       PRINT STRING ("GET STMT fails -")
       PRINT (R,8,0)
       NEWLINE
   FINISH 
FINISH 
IF  R#0 THEN  RETURN 
R = CLASSIFY STMT C 
    (ST,FG,LBLSTR,PREDSTR,CALLSTR,DESTR,PFSTR,CFSTR,DFSTR)
IF  DIAGOP#0 THEN  START 
   IF  R#5 THEN  START 
       PRINT STRING ("CLASSIFY STMT fails -")
       PRINT (R,8,0)
       NEWLINE
   FINISH 
FINISH 
R = R - 5
PS = ""
END 
!
!
ROUTINE  CHECK HDR
IF  SET UP=0 THEN  START 
    IF  R#0 THEN  RETURN 
    APARAM C 
        (PS,CALL PARMS,MAXPCT,KNTXT,MAXKNL,PVAL,PCT,R)
    IF  R>=0 THEN  R = 0
FINISH  ELSE  START 
    IF  DIAGOP#0 THEN  START 
       IF  R#0 THEN  START 
           PRINT STRING ("ANALYSE CALL fails -")
           PRINT (R,8,0)
           NEWLINE
       FINISH  ELSE  START 
           IF  RN#MAC NAME THEN  START 
               PRINT STRING ("Wrong name found - ".RN.NLSTRING)
           FINISH 
       FINISH 
    FINISH 
    IF  R#0 OR  RN#MAC NAME THEN  R = -1
FINISH 
END 
!
!
!
IF  SET UP=0 THEN  CALL PARMS = ""
! **** **** FOR TESTING ONLY **** ****
IF  DIAGOP#0 THEN  START 
   BEGIN 
       INTEGER  J
       PRINT STRING ("Macro text:")
       NEWLINE
       FOR  J=1,1,TEXT BOUND&X'00FFFFFF' CYCLE 
           PRINT SYMBOL (BYTE INTEGER(TEXT ADDRESS+J-1))
       REPEAT 
       PRINT STRING ("<< End of text")
       NEWLINE
   END 
FINISH 
! **** **** END OF TESTING CODE **** ****
FAIL FLAG = 0
BMARK = 0
! MAKE THE TEXT ACCESSIBLE AS A NEW LEVEL OF INPUT, SIGNALLING
! EOF AT END:
NEW LEVEL (TEXT BOUND,TEXT ADDRESS,1,R)
IF  DIAGOP#0 THEN  START 
   PRINT LEVELS
FINISH 
IF  R#0 THEN  START 
    FAIL FLAG = X'00001000'
    -> SIGNAL FAULT
FINISH 
! TRY IT 'WITH BRACKETS' AND SUPPRESS DOUBLE QUOTE CONTRACTION:
IF  DIAGOP#0 THEN  START 
   PRINT STRING ("Trying ""with brackets"" -".NLSTRING)
FINISH 
GET AND CLASSIFY (1)
IF  R#0 THEN  -> TRY NOBRACKETS
ANALYSE CALL B (CALLSTR,CFSTR,RN,PS,R)
CHECK HDR
IF  R#0 THEN  -> TRY NOBRACKETS
BMARK = -1
IF  CFSTR->PFSTR.("D").DFSTR THEN  -> USE MACRO
!
TRY NOBRACKETS:
RESTART THIS LEVEL
IF  DIAGOP#0 THEN  START 
   PRINT STRING ("Trying ""without brackets"" -".NLSTRING)
FINISH 
GET AND CLASSIFY (0)
IF  R#0 THEN  -> MAC NO GOOD
ANALYSE CALL N (CALLSTR,CFSTR,RN,PS,R)
CHECK HDR
IF  R#0 THEN  -> MAC NO GOOD
BMARK = 0
!
USE MACRO:
!
IF  SET UP=0 THEN  START 
    MAC NAME = RN
    ABANDON LEVEL
FINISH  ELSE  START 
    APARAM C 
        (PS,CALL PARMS,MAXPCT,KNTXT,MAXKNL,PVAL,PCT,R)
    ! TREAT UNRECOGNISED KEYWORDS, WRAP-AROUND AND
    ! DOUBLE SPECIFICATION OF PARAMETERS AS FAULTS:
    IF  R&X'000000E0'#0 THEN  R = R ! X'80000000'
    IF  R<0 THEN  START 
        FAIL FLAG = R
        -> DROP
    FINISH 
    IF  R#0 THEN  START 
        ! THESE ARE ONLY WARNINGS.  FAILURES HAVE BEEN DEALT
        ! WITH BY THE "R<0" CONDITION ABOVE.
        PRINT ERRORS (R, PARAM ETEXTS)
    FINISH 
    USE AS MACRO (PCT,KNTXT,PVAL,SSOWN_BRACKET FLAG,R)
    IF  R#0 THEN  START 
        FAIL FLAG = R
        -> DROP
    FINISH 
    SSOWN_BRACKET FLAG = BMARK
FINISH 
RETURN 
!
MAC NO GOOD:
IF  BMARK=-1 THEN  -> USE MACRO
FAIL FLAG = X'00000800'
!
DROP:
ABANDON LEVEL
SIGNAL FAULT:
FAIL FLAG = FAIL FLAG ! X'80000000'
RETURN 
!
END 
!
!
EXTERNAL  ROUTINE  OBEY JOB (STRING  (255) DUMMY)
!
INTEGER  KNOWN MACS
! MAC LIMIT IS THE MAXIMUM NUMBER OF MACRO DECLARATIONS
! WHICH CAN BE HANDLED IN ONE JOB OR SESSION.
CONST  INTEGER  MAC LIMIT = 24
RECORD (PD) ARRAY  MAC TEXT (1:MAC LIMIT)
RECORD (PD) ARRAY  MAC NAME (1:MAC LIMIT)
STRING  (255) IN, STMT, FLAGS, LBL, PRED, CALL, DEST
STRING  (255) XBL, DESTINATION, PFLAGS, CFLAGS, DFLAGS
STRING  (80) OLD D1, OLD D2
STRING  (1) NLSTRING
INTEGER  R, ACT, STATE BEFORE WHEN, LAST STATE, LBLF, CH DISCARD
INTEGER  COND, ONLINE, REMPTR, INNER CALL, LAST BRACKET FLAG
INTEGER  OUTER WARNING, OUTER STATE, BASE LEVEL
INTEGER  TAKE ELSE, TRAP BITS, SYNTAX RESULT
INTEGER  CFILEBASE, CFILESIZE, CONFLAG, RETURN NOW
RECORD (RF) IN FILE DETAILS
! I HAVE TWO VERSIONS OF THE MAIN SWITCH IN THE INTERPRETER.
! ONE IS SLIGHTLY MORE COMPACT, AND THE OTHER IS (I THINK)
! SIMPLER.  I AM USING THE 'SIMPLER' VERSION, BUT THE
! 'COMPACT' CODE IS HELD IN THIS FILE AFTER %END %OF %FILE.
! THERE ARE COMMENTS ABOUT RELATED CHANGES IN OTHER PARTS OF THE
! CODE - NOT MANY OF THEM.
!
STRING  (15) LABEL PROMPT
INTEGER  CURRENT PROMPT
CONST  BYTE  INTEGER  ARRAY  PROMPT FOR STATE (1:9) = C 
    1,  0,  3,  2,  4,  2,  4,  4,  2
CONST  STRING  (8) ARRAY  PROMPT STRINGS (1:4) = C 
    "Control:",
    "Command:",
    ".ELSE?",
    ".FINISH?"
!
SWITCH  ACTION (1:22); ! (1:48) FOR THE 'COMPACT' CODE.
CONST  BYTE  INTEGER  ARRAY  ACT TABLE (0:14,1:9) = C 
  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  1, 16,  3, 17,  5, 18, 18, 18, 19, 20, 21, 12, 18, 18, 22,
 23, 16,  3, 25, 26, 39, 27, 28, 28, 28, 29, 32, 39, 39, 34,
 23,  2,  3, 37, 26, 38, 27, 28, 28, 28, 30, 32, 40, 41, 42,
 23, 16,  3, 25, 26, 39, 27, 28, 28, 28, 31, 33, 39, 39, 34,
 23,  2,  3, 37, 26, 38, 27, 28, 28, 28, 31, 32, 40, 41, 42,
 23, 16,  3, 25, 26, 39, 27, 28, 28, 28, 30, 33, 39, 39, 34,
 23, 16,  3, 25, 26, 39, 27, 28, 28, 28, 31, 33, 48, 48, 48,
 23, 43, 44, 45, 26, 46, 27, 28, 28, 28, 31, 47, 48, 48, 48
! %CONST %STRING (64) %ARRAY CLASS TEXT (0:14) = "Unrecognised",
!     "Opening data delimiter",
!     "Opening data delimiter after incomplete statement",
!     "Incomplete statement before end-of file",
!     "Statement too long",
!     "Simple call",
!     ".GOTO",
!     ".IF .GOTO",
!     ".IF .THEN",
!     ".IF .START",
!     ".ELSE",
!     ".FINISH",
!     ".WHENEVER .GOTO",
!     ".WHENEVER .THEN",
!     ".WHENEVER .START"
!
INTEGER  NST, TEMASK; ! NOT NEEDED FOR THE 'COMPACT' CODE.
! THE ARRAY 'NEXT STATE' IS NOT NEEDED EITHER FOR THE 'COMPACT' CODE:
CONST  BYTE  INTEGER  ARRAY  NEXT STATE (1:48) = C 
         0,  X'C0',  X'C0',  X'CA',      0,      0,      0,      0,
     X'C0',  X'C3',  X'C0',      0,      0,      0,      0,  X'C0',
     X'CA',      0,  X'C0',  X'C7',      0,  X'C8',  X'C0',      0,
     X'CA',  X'C0',  X'C0',  X'C0',  X'C6',  X'C5',  X'C0',      1,
         0,  X'C8',      0,      0,  X'CA',  X'C0',  X'C0',  X'C0',
     X'C0',  X'C0',  X'C0',  X'C0',  X'CA',  X'C0',      0,  X'C0'
!
! THE ARRAY 'ACTNR' IS NOT NEEDED FOR THE 'COMPACT' CODE.
CONST  BYTE  INTEGER  ARRAY  ACTNR (1:48) = C 
      1,   2,   3,   4,   1,   6,   7,   8,
      9,  10,  11,   1,  13,  14,  15,   3,
      1,   1,  19,  22,  21,  22,   1,   0,
      1,   1,   1,   1,  20,  20,   1,   1,
      5,  22,   0,   0,   4,   6,   1,  13,
     14,  15,  18,  18,  17,  16,  12,   1
!
CONST  BYTE  INTEGER  ARRAY  CONTEXT WARNING (1:48) = C 
      1,  0,  3,  4,  6,  0,  0,  0,
      0,  0,  0,  8,  0,  0,  0,  0,
     14,  0,  0,  0,  0,  0,  1,  0,
      5,  6, 10, 12,  0,  0,  7,  0,
      0,  0,  0,  0,  4,  0,  0,  0,
      0,  0,  0,  3,  5,  0,  0, 13
!
! THE ARRAY 'WARNING TEXTS' HAS BEEN REPLACED BY THE TWO
! ARRAYS 'WTX' AND 'WNDX', BUT 'WARNING TEXTS' IS LEFT AS
! A COMMENT SINCE IT IS EASIER TO READ.
! %CONST %STRING (48) %ARRAY WARNING TEXTS (1:22) = %C
!     "Unrecognisable text",
!     "Unexpected data",
!     "Incomplete statement before data",
!     "Statement incomplete before end-of-file",
!     "End-of-file",
!     "Statement too long",
!     ".ELSE out of context",
!     ".FINISH out of context",
!     "LABEL out of context",
!     ".GOTO out of context",
!     "CALL out of context - ignored",
!     "Nested .IF - ignored",
!     "Nested .WHENEVER - ignored",
!     "Label missing",
!     "Data terminator missing",
!     "Unacceptable form of call",
!     "Destination not a valid label",
!     "Macro declaration fails",
!     "Macro call fails",
!     "Predicate invalid",
!     "no space for .WHENEVER text",
!     "Parameters invalid"
!
!
CONST  HALF  INTEGER  ARRAY  WNDX (1:22) = C 
      0,
     20,
     36,
     69,
    109,
    121,
    140,
    161,
    184,
    205,
    226,
    256,
    277,
    304,
    318,
    342,
    368,
    398,
    422,
    439,
    457,
    485
!
CONST  BYTE  INTEGER  ARRAY  WTX (0:503) = C 
19, 'U','n','r','e','c','o','g','n','i','s','a','b','l','e',
    ' ','t','e','x','t',
15, 'U','n','e','x','p','e','c','t','e','d',
    ' ','d','a','t','a',
32, 'I','n','c','o','m','p','l','e','t','e',
    ' ','s','t','a','t','e','m','e','n','t',
    ' ','b','e','f','o','r','e',
    ' ','d','a','t','a',
39, 'S','t','a','t','e','m','e','n','t',
    ' ','i','n','c','o','m','p','l','e','t','e',
    ' ','b','e','f','o','r','e',
    ' ','e','n','d','-','o','f','-','f','i','l','e',
11, 'E','n','d','-','o','f','-','f','i','l','e',
18, 'S','t','a','t','e','m','e','n','t',
    ' ','t','o','o',
    ' ','l','o','n','g',
20, '.','E','L','S','E',
    ' ','o','u','t',
    ' ','o','f',
    ' ','c','o','n','t','e','x','t',
22, '.','F','I','N','I','S','H',
    ' ','o','u','t',
    ' ','o','f',
    ' ','c','o','n','t','e','x','t',
20, 'L','a','b','e','l',
    ' ','o','u','t',
    ' ','o','f',
    ' ','c','o','n','t','e','x','t',
20, '.','G','O','T','O',
    ' ','o','u','t',
    ' ','o','f',
    ' ','c','o','n','t','e','x','t',
29, 'C','a','l','l',
    ' ','o','u','t',
    ' ','o','f',
    ' ','c','o','n','t','e','x','t',
    ' ','-',
    ' ','i','g','n','o','r','e','d',
20, 'N','e','s','t','e','d',
    ' ','.','I','F',
    ' ','-',
    ' ','i','g','n','o','r','e','d',
26, 'N','e','s','t','e','d',
    ' ','.','W','H','E','N','E','V','E','R',
    ' ','-',
    ' ','i','g','n','o','r','e','d',
13, 'L','a','b','e','l',
    ' ','m','i','s','s','i','n','g',
23, 'D','a','t','a',
    ' ','t','e','r','m','i','n','a','t','o','r',
    ' ','m','i','s','s','i','n','g',
25, 'U','n','a','c','c','e','p','t','a','b','l','e',
    ' ','f','o','r','m',
    ' ','o','f',
    ' ','c','a','l','l',
29, 'D','e','s','t','i','n','a','t','i','o','n',
    ' ','n','o','t',
    ' ','a',
    ' ','v','a','l','i','d',
    ' ','l','a','b','e','l',
23, 'M','a','c','r','o',
    ' ','d','e','c','l','a','r','a','t','i','o','n',
    ' ','f','a','i','l','s',
16, 'M','a','c','r','o',
    ' ','c','a','l','l',
    ' ','f','a','i','l','s',
17, 'P','r','e','d','i','c','a','t','e',
    ' ','i','n','v','a','l','i','d',
27, 'N','o',
    ' ','s','p','a','c','e',
    ' ','f','o','r',
    ' ','.','W','H','E','N','E','V','E','R',
    ' ','t','e','x','t',
18, 'P','a','r','a','m','e','t','e','r','s',
    ' ','i','n','v','a','l','i','d'
!
!
!
CONST  STRING  (9) CTU = ".CONTINUE"
CONST  STRING  (9) CTF = "CCCCCCCCC"
!
!
CONST  INTEGER  IDENTIFIERS = 19
CONST  INTEGER  VARIABLES = 11
CONST  INTEGER  CONDITIONS = 6
CONST  INTEGER  COND LIM = 18; ! MUST BE VARIABLES + CONDITIONS + 1.
!
!
INTEGER  ARRAY  VARS (1:VARIABLES)
INTEGER  NAME  RETURN CODE, PROG FLAG, CMND FLAG, LOAD FLAG, JOB FLAG
INTEGER  NAME  FILE FLAG
INTEGER  NAME  RESULT A, RESULT B, RESULT C, RESULT D
INTEGER  NAME  COUNTER
!
RECORD  FORMAT  TRAP (INTEGER  CLASS, BOUND, ADDRESS)
RECORD (TRAP) ARRAY  WHEN ACTION (1:CONDITIONS)
RECORD (TRAP) WHEN SPEC
INTEGER  WHEN CONDITION
! TRAPS ARE:
!   1 FOR USER RESULT NON-ZERO
!   2 FOR PROGRAM FAILURE
!   3 FOR COMMAND FAILURE (I.E., NON-ZERO RESULT FROM SUBSYS COMMAND)
!   4 FOR LOADER FAILURES (E.G., ROUTINE NOT FOUND)
!   5 FOR JOB FAILURES - MOSTLY JCL ERRORS
!   6 FOR FILE FAILURES (IF WE EVER DISTINGUISH THEM FROM
!     COMMAND FAILURES)
!
!
!
IF  ULCEQUIV=0 THEN  START 
    INTEGER  FN  SPEC  RECOGNISE IDENTIFIER (STRING  NAME  N)
    ROUTINE  SPEC  CLOSE UP (STRING  NAME  S)
FINISH  ELSE  START 
    INTEGER  FN  SPEC  RECOGNISE IDENTIFIER (STRING  (80) N)
FINISH 
ROUTINE  SPEC  COPY TO STRING (RECORD (PD) NAME  D, STRING  NAME  S)
INTEGER  FN  SPEC  EVAL
ROUTINE  SPEC  SPRING TRAP (INTEGER  N)
IF  DIAGOP#0 THEN  START 
   ROUTINE  SPEC  LIST TRAPS
FINISH 
ROUTINE  SPEC  SAVE BYTES (INTEGER  BOUND, ADDRESS, INTEGER  NAME  F)
ROUTINE  SPEC  SAVE COND (STRING  NAME  P, F, INTEGER  T)
ROUTINE  SPEC  SAVE CALL IN SEQUENCE (STRING  NAME  C)
ROUTINE  SPEC  SAVE STRINGS (STRING  NAME  C, F)
ROUTINE  SPEC  STOW WHEN ACTION
ROUTINE  SPEC  DEAL WITH MACRO C 
    (INTEGER  NAME  Q, STRING  NAME  OPENDATA, CLOSEDATA)
ROUTINE  SPEC  DO CALL (STRING  NAME  C, F, INTEGER  NAME  WF, FM, TRB)
ROUTINE  SPEC  RESTORE VALUES
!
!
!
!
NLSTRING = TOSTRING (NL)
OLD D1 = SSOWN_D DELIM 1
OLD D2 = SSOWN_D DELIM 2
LAST BRACKET FLAG = SSOWN_BRACKET FLAG
OUTER WARNING = SSOWN_WARNING NUMBER
OUTER STATE = SSOWN_STATE
INNER CALL = SSOWN_MAC INITIALISED
RETURN NOW = 0
BEGIN 
INTEGER  KCT, D
STRING  (8) ARRAY  KEYSTRING (1:3)
RECORD (PD) ARRAY  TEXT VALUE (1:3)
STRING  (255) TVAL
TVAL = "JOB,JOURNAL,BRACKETS"
APARAM (TVAL, DUMMY, 3, KEYSTRING, 8, TEXT VALUE, KCT, D)
COPY TO STRING (TEXT VALUE (1), TVAL)
IF  TVAL="" THEN  START 
    IF  INNER CALL#0 THEN  START 
        PRINT STRING ("**** Job file name missing")
        NEWLINE
        SET RETURN CODE (5)
        RETURN NOW = -1
    FINISH  ELSE  START 
        START MACROUTINES (0,0,D)
        ONLINE = -1
    FINISH 
FINISH  ELSE  START 
    ONLINE = 0
    CONNECT (TVAL, 1, 0, 0, IN FILE DETAILS, CONFLAG)
    IF  CONFLAG#0 THEN  START 
        PRINT STRING ("**** Cannot connect job file")
        NEWLINE
        SET RETURN CODE (7)
        RETURN NOW = -1
    FINISH  ELSE  START 
        CFILEBASE = IN FILE DETAILS_ADDR + IN FILE DETAILS_START
        CFILESIZE = IN FILE DETAILS_LIMIT - IN FILE DETAILS_START
        START MACROUTINES (X'18000000'!CFILESIZE,CFILEBASE,D)
        IF  D#0 THEN  START 
            PRINT ERRORS (X'00001000',MACRO ETEXTS)
            SET RETURN CODE (2)
            RETURN NOW = -1
        FINISH 
    FINISH 
FINISH 
COPY TO STRING (TEXT VALUE (2), TVAL)
IF  TVAL#"" THEN  START 
    ! **** **** SELECT OUTPUT **** ****
FINISH 
COPY TO STRING (TEXT VALUE (3), TVAL)
IF  INNER CALL=0 THEN  SSOWN_BRACKET FLAG = UINFI (16)
IF  LENGTH(TVAL)>=1 THEN  START 
    D = BYTE INTEGER(ADDR(TVAL)+1)
    IF  D='Y' THEN  SSOWN_BRACKET FLAG = -1
    IF  D='N' THEN  SSOWN_BRACKET FLAG = 0
FINISH 
END 
IF  RETURN NOW#0 THEN  START 
    RESTORE VALUES
    RETURN 
FINISH 
IF  SSOWN_KWD MAX SIZE#MAXKNL THEN  START 
    PRINT STRING ("**** Confusion about keyword size".NLSTRING)
    SET RETURN CODE (1)
    ABANDON LEVEL
    RESTORE VALUES
    RETURN 
FINISH 
!
BASE LEVEL = SSOWN_IN SOURCE
INIT CLI VARS
SSOWN_D DELIM 1 = DATA START MARK
SSOWN_D DELIM 2 = DATA END MARK
IF  SSOWN_SAVE BASE=0 THEN  START 
    SSOWN_SAVE LIM = 8192
    OUTFILE ("T#CLISAVE",SSOWN_SAVE LIM,0,8,SSOWN_SAVE BASE,CONFLAG)
    SSOWN_SAVE LIM = SSOWN_SAVE BASE + SSOWN_SAVE LIM
    SSOWN_SAVE PTR = SSOWN_SAVE BASE
FINISH 
RETURN CODE == VARS (1)
PROG FLAG == VARS (2)
CMND FLAG == VARS (3)
LOAD FLAG == VARS (4)
JOB FLAG == VARS (5)
FILE FLAG == VARS (6)
RESULT A == VARS (7)
RESULT B == VARS (8)
RESULT C == VARS (9)
RESULT D == VARS (10)
COUNTER == VARS (11)
RETURN NOW = 0
BEGIN 
INTEGER  I, CTE, CTL
FOR  I=1,1,VARIABLES CYCLE 
    VARS (I) = 0
REPEAT 
!
WHEN SPEC_CLASS = 0
WHEN SPEC_BOUND = 0
WHEN SPEC_ADDRESS = 0
FOR  I=1,1,CONDITIONS CYCLE ; ! USED TO %CYCLE FROM 2 TO AVOID SETTING
                         ! SETTING A CLASS 0 TRAP FOR 'URNZ'.
    WHEN ACTION (I) = WHEN SPEC
REPEAT 
!
CTL = LENGTH (CTU) + 1
SAVE BYTES (CTL, ADDR(CTU), CTE)
SAVE BYTES (CTL, ADDR(CTF), CTE)
IF  CTE#0 THEN  START 
    PRINT STRING ("**** No work space")
    NEWLINE
    SET RETURN CODE (3)
    RETURN NOW = -1
FINISH ; ! %ELSE %START - USED TO SET A CLASS 2 TRAP
         !                WITH '.CONTINUE' TO HANDLE 'URNZ'.
         !                NO LONGER NECESSARY - SEE ABOVE.
         !     WHEN SPEC_CLASS = 2
         !     WHEN SPEC_BOUND = CTL
         !     WHEN SPEC_ADDRESS = SSOWN_SAVE BASE
         !     WHEN ACTION (1) = WHEN SPEC
         ! %FINISH
!
END 
IF  RETURN NOW#0 THEN  START 
    ABANDON LEVEL
    RESTORE VALUES
    RETURN 
FINISH 
!
SSOWN_STATE = 1
TAKE ELSE = 0
SSOWN_ACCUMULATING = 0
KNOWN MACS = 0
SSOWN_LAST PROMPT = -1
!
! THIS ROUTINE IS DRIVEN BY THE VALUE OF 'SSOWN_STATE', WHICH REPRESENTS THE
! CURRENT CONDITION OF THE JOB CONTROL PROGRAM, AND BY THE 'STATEMENT
! CLASS' OF THE STATEMENT JUST READ.  THE MAIN LOOP OF THE ROUTINE
! STARTS IMMEDIATELY AFTER THIS COMMENT, AND EXITS ONLY WHEN 'STATE'
! ACQUIRES THE VALUE 10 (JOB COMPLETE).  WITHIN THE LOOP, A SINGLE
! STATEMENT IS READ AND CLASSIFIED, AND THE CLASS NUMBER AND 'STATE'
! ARE USED TO SELECT APPROPRIATE PROCESSING VIA THE ARRAY 'ACT TABLE'
! AND THE SWITCH 'ACTION'.
! VALUES OF 'STATE' ARE:
!   1 - NORMAL: OBEY ANYTHING.
!       THIS STATE IS ACTUALLY SUBDIVIDED.  NORMALLY 'TAKE ELSE=0', SO
!       A LINE STARTING WITH '.ELSE' IS REJECTED.  IF THE LAST LINE WAS
!       '.IF ... .THEN ...', WE HAVE 'TAKE ELSE=1' MEANING "THE
!       PREDICATE WAS TRUE, SO ACCEPT A LINE STARTING '.ELSE' BUT DO NOT
!       EXECUTE ITS CALL", OR ELSE WE HAVE 'TAKE ELSE=2' MEANING "THE
!       PREDICATE WAS FALSE, SO ACCEPT A LINE STARTING '.ELSE' AND DO
!       THE CALL".  IF WE HAVE 'TAKE ELSE=1', AND WE DO IN FACT FIND
!       AN '.ELSE' WITH A CALL (WHICH IS NOT, OF COURSE, TO BE
!       EXECUTED), THEN 'TAKE ELSE' GETS THE VALUE 3 (TEMPORARILY) TO
!       ALLOW ANY '.DATA' TO BE SKIPPED.
!   2 - SKIPPING FOR LABEL.
!       THIS IS ALSO SUBDIVIDED BY THE VALUE OF 'TAKE ELSE'.  HERE,
!       OF COURSE, THERE IS NO QUESTION OF OBEYING THE CALL ON AN
!       '.ELSE' LINE, SINCE SUCH A LINE CANNOT (VALIDLY) BE LABELLED.
!       THE INTERPRETER NEVERTHELESS RECOGNISES SUCH LINES AS PART OF
!       ITS PRECAUTIONS AGAINST 'BRANCHING INTO CONDITIONALS'.
!   3 - SKIPPING FIRST HALF OF AN '.IF ... .START ... .ELSE ... .FINISH'
!       CONSTRUCTION (BECAUSE THE PREDICATE WAS FALSE).
!   4 - OBEYING THE FIRST HALF (BECAUSE THE PREDICATE WAS TRUE).
!   5 - SKIPPING THE SECOND HALF (AFTER OBEYING THE FIRST, BECAUSE THE
!       PREDICATE WAS TRUE).
!   6 - OBEYING THE SECOND HALF (AFTER SKIPPING THE FIRST, BECAUSE THE
!       PREDICATE WAS FALSE).
!   7 - SKIPPING THE WHOLE CONSTRUCTION, E.G., WHILE LOOKING FOR A
!       LABEL.
!   8 - SKIPPING OVER A '.WHENEVER ... .FINISH' CONSTRUCTION.
!   9 - SSOWN_ACCUMULATING THE TEXT OF A '.WHENEVER ... .FINISH' CONSTRUCTION.
!  10 - JOB COMPLETE - DUE TO CLOSE DOWN.
!
! STATEMENT CLASSES ARE:
!    0    "UNRECOGNISED"
!    1    "OPENING DATA DELIMITER"
!    2    "OPENING DATA DELIMITER AFTER INCOMPLETE STATEMENT"
!    3    "INCOMPLETE STATEMENT BEFORE END-OF-FILE"
!    4    "STATEMENT TOO LONG"
!    5    "SIMPLE CALL"
!    6    ".GOTO"
!    7    ".IF .GOTO"
!    8    ".IF .THEN"
!    9    ".IF .START"
!   10    ".ELSE"
!   11    ".FINISH"
!   12    ".WHENEVER .GOTO"
!   13    ".WHENEVER .THEN"
!   14    ".WHENEVER .START"
!
!
UNTIL  SSOWN_STATE=10 CYCLE 
    TRAP BITS = 0
    CURRENT PROMPT = PROMPT FOR STATE (SSOWN_STATE)
    IF  CURRENT PROMPT#SSOWN_LAST PROMPT THEN  START 
        IF  CURRENT PROMPT=0 C 
        THEN  PROMPT (LABEL PROMPT) C 
        ELSE  PROMPT (PROMPT STRINGS(CURRENT PROMPT))
        SSOWN_LAST PROMPT = CURRENT PROMPT
    FINISH 
    WHILE  NL#SSOWN_LAST CHAR READ#25 CYCLE 
        CH DISCARD = MASTER CHAR IN (1)
    REPEAT 
    ! GET STATEMENT, CLASSIFY STATEMENT, INITIAL PROCESSING, ETC.
    GET STMT (SSOWN_BRACKET FLAG, 0, SSOWN_COMMENTF, SSOWN_D DELIM 1, SSOWN_CONTU, SSOWN_XSTMT, C 
        IN, STMT, FLAGS, R)
    ! FIRST PARAMETER SHOULD BE NON-ZERO FOR BRACKET OPTION.
    IF  R=-1 THEN  START 
        PRINT STRING ("**** GET STMT: bad parameters".NLSTRING)
        SSOWN_STATE = 10
        -> ACT DONE
    FINISH 
    IF  DIAGOP#0 THEN  START 
       PRINT STRING ("Raw statement:")
       NEWLINE
    FINISH 
    IF  ONLINE=0 THEN  START 
        PRINT STRING (IN)
        NEWLINE
    FINISH 
    IF  DIAGOP#0 THEN  START 
       PRINT STRING ("Reconstructed as:")
       NEWLINE
       PRINT STRING (STMT)
       NEWLINE
       PRINT STRING (FLAGS)
       NEWLINES (2)
    FINISH 
    IF  R=0 C 
    THEN  R = CLASSIFY STMT (STMT,FLAGS,LBL,PRED,CALL,DEST, C 
        PFLAGS, CFLAGS, DFLAGS)
    LBLF = 0
    IF  DIAGOP#0 THEN  START 
       PRINT STRING ("Classified as - ")
       PRINT STRING (CLASS TEXT(R))
       NEWLINE
    FINISH 
    IF  R>4 THEN  START 
        IF  DIAGOP#0 THEN  START 
           IF  10#R#11 THEN  START 
               IF  LBL="" THEN  START 
                   PRINT STRING ("    Unlabelled")
                   NEWLINE
               FINISH  ELSE  START 
                   PRINT STRING ("    Label """.LBL."""")
                   NEWLINE
               FINISH 
           FINISH 
           IF  7<=R<=9 OR  12<=R<=14 THEN  START 
               PRINT STRING ("    Predicate """.PRED."""")
               NEWLINE
               PRINT STRING ("               ".PFLAGS)
               NEWLINE
           FINISH 
!          %IF R=5 %OR R=8 %OR R=10 %OR R=13 %THEN %START
           IF  R=8 OR  R=10 OR  R=13 THEN  START 
               PRINT STRING ("    Call """.CALL."""")
               NEWLINE
               PRINT STRING ("          ".CFLAGS)
               NEWLINE
           FINISH 
           IF  R=6 OR  R=7 OR  R=12 THEN  START 
               PRINT STRING ("    Destination """.DEST."""")
               NEWLINE
               PRINT STRING ("                 ".DFLAGS)
               NEWLINE
           FINISH 
        FINISH 
        IF  (3<=SSOWN_STATE<=9 OR  R=10 OR  R=11) C 
        AND  LBL#"" C 
        THEN  START 
            LBLF = -1
            XBL = LBL
            LBL = ""
        FINISH 
        IF  SSOWN_STATE=2 AND  LBL=DESTINATION THEN  START 
            SSOWN_STATE = 1
            TAKE ELSE = 0
        FINISH 
    FINISH 
    ACT = ACT TABLE (R, SSOWN_STATE)
    NST = NEXT STATE (ACT); ! NOT NEEDED FOR THE 'COMPACT' CODE.
    TEMASK = NST >> 6;      ! NOT NEEDED FOR THE 'COMPACT' CODE.
    NST = NST & X'3F';      ! NOT NEEDED FOR THE 'COMPACT' CODE.
    SSOWN_WARNING NUMBER = CONTEXT WARNING (ACT)
    -> ACTION (ACTNR(ACT)); ! -> ACTION (ACT) IN THE 'COMPACT' CODE.
!
! THIS IS THE START OF THE AREA OF CODE WHICH CAN BE REPLACED
! BY THE 'COMPACT' SWITCH FILED AFTER %END %OF %FILE.
ACTION (2):
    UNLESS  0#TAKE ELSE#1 THEN  SSOWN_WARNING NUMBER = 2
ACTION (3):
    GATHER DATA (SSOWN_D DELIM 2, 1)
    -> ACT DONE
!
ACTION (17):
    ! TIDY SSOWN_ACCUMULATION (0)
    SSOWN_ACCUMULATING = 0
    SSOWN_ACCUMULATION_BOUND = SSOWN_ACCUMULATION_BOUND ! X'18000000'
    -> ACT DONE
!
ACTION (4):
    IF  STMT="" THEN  SSOWN_WARNING NUMBER = 5
    -> ACT DONE
!
ACTION (6):
    DO CALL (CALL,CFLAGS,SSOWN_WARNING NUMBER,SYNTAX RESULT,TRAP BITS)
    -> ACT DONE
!
ACTION (8):
    COND = EVAL
    IF  COND=0 THEN  -> ACT DONE
ACTION (7):
    DESTINATION = PURGE (DEST,DFLAGS,REMPTR)
    IF  REMPTR<=LENGTH(DEST) OR  DESTINATION="" OR  DESTINATION="-" C 
    THEN  SSOWN_WARNING NUMBER = 17 C 
    ELSE  START 
        IF  BYTE INTEGER(ADDR(DESTINATION)+1)='-' THEN  START 
            GO BACK
            DESTINATION = C 
                SUBSTRING (DESTINATION, 2, LENGTH(DESTINATION))
        FINISH 
        IF  ULCEQUIV#0 THEN  START 
            UCTRANSLATE (ADDR(DESTINATION)+1, LENGTH(DESTINATION))
        FINISH 
        IF  LENGTH(DESTINATION)>13 C 
        THEN  LABEL PROMPT = SUBSTRING (DESTINATION,1,13).":?" C 
        ELSE  LABEL PROMPT = DESTINATION.":?"
        SSOWN_LAST PROMPT = -1
        SSOWN_STATE = 2; ! SCANNING FOR LABEL
    FINISH 
    -> ACT DONE
!
ACTION (9):
    COND = EVAL
    IF  COND#0 THEN  START 
        DO CALL (CALL,CFLAGS,SSOWN_WARNING NUMBER,SYNTAX RESULT,TRAP BITS)
        TAKE ELSE = 1
    FINISH  ELSE  TAKE ELSE = 2
    -> ACT DONE
!
ACTION (10):
    COND = EVAL
    IF  COND#0 THEN  NST = 4; ! %ELSE NST = 3
    ! BUT IT ALREADY IS 3 - SEE TABLE 'NEXT STATE'.
    ! OBEY FIRST HALF OR SKIP TO SECOND HALF
ACTION (22):
    LAST STATE = SSOWN_STATE
    -> ACT DONE
!
ACTION (11):
    IF  TAKE ELSE#1 THEN  START 
        IF  TAKE ELSE=2 C 
        THEN  DO CALL C 
            (CALL,CFLAGS,SSOWN_WARNING NUMBER,SYNTAX RESULT,TRAP BITS) C 
        ELSE  SSOWN_WARNING NUMBER = 7
        TAKE ELSE = 0
    FINISH  ELSE  TAKE ELSE = 3
    -> ACT DONE
!
ACTION (13):
    DESTINATION = PURGE (DEST,DFLAGS,REMPTR)
    IF  REMPTR<=LENGTH(DEST) C 
    OR  DESTINATION="" C 
    OR  BYTE INTEGER(ADDR(DESTINATION)+1)='-' C 
    THEN  SSOWN_WARNING NUMBER = 17 C 
    ELSE  START 
        IF  ULCEQUIV#0 THEN  START 
            UCTRANSLATE (ADDR(DESTINATION)+1, LENGTH(DESTINATION))
        FINISH 
        SAVE COND (PRED,PFLAGS,1)
        IF  SSOWN_WARNING NUMBER=0 THEN  SAVE STRINGS (DESTINATION,SSOWN_NULLSTRING)
    FINISH 
    -> ACT DONE
!
ACTION (14):
    SAVE COND (PRED,PFLAGS,2)
    IF  SSOWN_WARNING NUMBER=0 THEN  SAVE STRINGS (CALL,CFLAGS)
    -> ACT DONE
!
ACTION (15):
    SAVE COND (PRED,PFLAGS,3)
    IF  SSOWN_WARNING NUMBER=0 THEN  START 
        STATE BEFORE WHEN = SSOWN_STATE
        SSOWN_STATE = 9; ! ACCUMULATING WHENEVER TEXT
    FINISH 
    ! SHOULD WE NOT DO SOMETHING ABOUT SKIPPING THE WHENEVER TEXT?
    -> ACT DONE
!
ACTION (19):
    TAKE ELSE = 1
    -> ACT DONE
!
ACTION (21):
    UNLESS  0#TAKE ELSE#3 THEN  SSOWN_WARNING NUMBER = 7
    -> ACT DONE
!
ACTION (20):
    IF  CALL#"" THEN  SSOWN_WARNING NUMBER = 11
    -> ACT DONE
!
ACTION (5):
    SSOWN_STATE = LAST STATE
    -> ACT DONE
!
ACTION (18):
    GATHER DATA (SSOWN_D DELIM 2, 2)
    -> ACT DONE
!
ACTION (16):
    SAVE CALL IN SEQUENCE (CALL)
    -> ACT DONE
!
ACTION (12):
    SSOWN_ACCUMULATING = 0
    WHEN SPEC_BOUND = SSOWN_SAVE PTR - WHEN SPEC_ADDRESS
    STOW WHEN ACTION
    SSOWN_STATE = STATE BEFORE WHEN
ACTION (1):
ACT DONE:
    ! THIS IS THE END OF THE SECTION OF CODE WHICH CAN BE
    ! REPLACED BY THE 'COMPACT' SWITCH.
    IF  NST#0 THEN  SSOWN_STATE = NST;    ! NOT NEEDED FOR 'COMPACT' CODE.
    TAKE ELSE = TAKE ELSE & TEMASK; ! NOT NEEDED FOR 'COMPACT' CODE.
    IF  LBLF#0 THEN  START 
        PRINT STRING ("**** Label ".XBL." out of context")
        NEWLINE
        TRAP BITS = TRAP BITS ! X'00000010'
    FINISH 
    IF  SSOWN_WARNING NUMBER#0 THEN  START 
        PRINT STRING (STARS.STRING(ADDR(WTX(WNDX(SSOWN_WARNING NUMBER)))))
        NEWLINE
        UNLESS  18#SSOWN_WARNING NUMBER#19 C 
        THEN  PRINT ERRORS (SYNTAX RESULT, MACRO ETEXTS)
        IF  SSOWN_WARNING NUMBER=20 C 
        THEN  PRINT ERRORS (SYNTAX RESULT, PRED ETEXTS)
        IF  SSOWN_WARNING NUMBER#5 THEN  TRAP BITS = TRAP BITS ! X'00000010'
    FINISH 
    BEGIN 
    INTEGER  I
    FOR  I=1,1,CONDITIONS CYCLE 
        IF  TRAP BITS&1#0 THEN  SPRING TRAP (I)
        TRAP BITS = TRAP BITS >> 1
    REPEAT 
    END 
REPEAT 
! THIS IS THE END OF THE MAIN LOOP OF THIS ROUTINE.
!
SET RETURN CODE (0)
CLEAR LEVEL (BASE LEVEL)
RESTORE VALUES
RETURN 
! THIS IS THE END OF THE MAIN ROUTINE.
!
!
!
IF  ULCEQUIV=0 THEN  START 
    INTEGER  FN  RECOGNISE IDENTIFIER (STRING  NAME  N)
    !
    ! THIS ROUTINE WILL RETURN ZERO UNLESS IT CAN MATCH 'N' IN THE ARRAY
    ! 'VN', IN WHICH CASE IT WILL RETURN THE INDEX OF THE MATCHING
    ! STRING, WHICH WILL LIE IN THE RANGE 1 TO 'IDENTIFIERS' INCLUSIVE.
    !
    ! THE TOTAL NUMBER OF IDENTIFIERS IS GIVEN BY 'IDENTIFIERS'.  THE NAMES
    ! MUST BE ARRANGED WITH INTEGERS FIRST, AND THEIR NUMBER IS GIVEN BY
    ! 'VARIABLES'.  AFTER THAT COME THE BOOLEANS, AND THE ONES TESTABLE BY
    ! 'WHENEVER' MUST COME FIRST.  'CONDITIONS' IS THE NUMBER OF THESE
    ! 'WHENEVER'-TESTABLE BOOLEANS.  THEIR CORRESPONDING INTEGER VALUES
    ! MUST APPEAR AT THE START OF THE INTEGER NAMES, IN THE SAME ORDER.
    ! IT IS ASSUMED ELSEWHERE IN THE CODE THAT 'URNZ' IS THE 'FIRST'
    ! CONDITION, AND THAT 'ANYFAIL' IS 18 AND 'ONLINE' IS 19.
    CONST  STRING  (11) ARRAY  VN (1:IDENTIFIERS) = "RESULT",
                                                    "PROGFLAG",
                                                    "CMNDFLAG",
                                                    "LOADFLAG",
                                                    "JOBFLAG",
                                                    "FILEFLAG",
                                                    "RESULTA",
                                                    "RESULTB",
                                                    "RESULTC",
                                                    "RESULTD",
                                                    "COUNTER",
                                                    "URNZ",
                                                    "PROGFAIL",
                                                    "CMNDFAIL",
                                                    "LOADFAIL",
                                                    "JOBFAIL",
                                                    "FILEFAIL",
                                                    "ANYFAIL",
                                                    "ONLINE"
    INTEGER  I
    I = IDENTIFIERS
    WHILE  I>=1 AND  VN(I)#N CYCLE 
        I = I - 1
    REPEAT 
    RESULT  = I
    END 
FINISH  ELSE  START 
    INTEGER  FN  RECOGNISE IDENTIFIER (STRING  (80) N)
    !
    ! THIS ROUTINE WILL RETURN ZERO UNLESS IT CAN MATCH 'N' IN THE ARRAY
    ! 'VN', IN WHICH CASE IT WILL RETURN THE INDEX OF THE MATCHING
    ! STRING, WHICH WILL LIE IN THE RANGE 1 TO 'IDENTIFIERS' INCLUSIVE.
    !
    ! THE TOTAL NUMBER OF IDENTIFIERS IS GIVEN BY 'IDENTIFIERS'.  THE NAMES
    ! MUST BE ARRANGED WITH INTEGERS FIRST, AND THEIR NUMBER IS GIVEN BY
    ! 'VARIABLES'.  AFTER THAT COME THE BOOLEANS, AND THE ONES TESTABLE BY
    ! 'WHENEVER' MUST COME FIRST.  'CONDITIONS' IS THE NUMBER OF THESE
    ! 'WHENEVER'-TESTABLE BOOLEANS.  THEIR CORRESPONDING INTEGER VALUES
    ! MUST APPEAR AT THE START OF THE INTEGER NAMES, IN THE SAME ORDER.
    ! IT IS ASSUMED ELSEWHERE IN THE CODE THAT 'URNZ' IS THE 'FIRST'
    ! CONDITION, AND THAT 'ANYFAIL' IS 18 AND 'ONLINE' IS 19.
    CONST  STRING  (11) ARRAY  VN (1:IDENTIFIERS) = "RESULT",
                                                    "PROGFLAG",
                                                    "CMNDFLAG",
                                                    "LOADFLAG",
                                                    "JOBFLAG",
                                                    "FILEFLAG",
                                                    "RESULTA",
                                                    "RESULTB",
                                                    "RESULTC",
                                                    "RESULTD",
                                                    "COUNTER",
                                                    "URNZ",
                                                    "PROGFAIL",
                                                    "CMNDFAIL",
                                                    "LOADFAIL",
                                                    "JOBFAIL",
                                                    "FILEFAIL",
                                                    "ANYFAIL",
                                                    "ONLINE"
    INTEGER  I
    UCTRANSLATE (ADDR(N)+1, LENGTH(N))
    I = IDENTIFIERS
    WHILE  I>=1 AND  VN(I)#N CYCLE 
        I = I - 1
    REPEAT 
    RESULT  = I
    END 
FINISH 
!
IF  ULCEQUIV=0 THEN  START 
    ROUTINE  CLOSE UP (STRING  NAME  S)
    INTEGER  I, J, L, C, A
    L = LENGTH (S)
    A = ADDR (S)
    I = 1
    J = 0
    WHILE  I<=L CYCLE 
        C = BYTE INTEGER (A+I)
        IF  C#' ' THEN  START 
            J = J + 1
            BYTE INTEGER (A+J) = C
        FINISH 
        I = I + 1
    REPEAT 
    LENGTH (S) = J
    END 
FINISH 
!
ROUTINE  COPY TO STRING (RECORD (PD) NAME  D, STRING  NAME  S)
INTEGER  L
! %INTEGER I, AS, AD; ! NOT NEEDED IF WE USE 'MOVE'
L = D_BOUND & X'00FFFFFF'
! AD = D_ADDRESS - 1; ! NOT NEEDED IF WE USE 'MOVE'.
! AS = ADDR (S); ! NOT NEEDED IF WE USE 'MOVE'.
! I = 1; ! NOT NEEDED IF WE USE 'MOVE'.
!
! **** **** MACHINE CODE **** ****
! %WHILE I<=L %CYCLE
!     BYTE INTEGER (AS+I) = BYTE INTEGER (AD+I)
!     I = I + 1
! %REPEAT
! EQUIVALENT TO:
MOVE (L, D_ADDRESS, ADDR(S)+1)
! **** **** END OF MACHINE CODE **** ****
!
LENGTH (S) = L
END 
!
!
ROUTINE  SPRING TRAP (INTEGER  N)
! N MUST LIE IN THE RANGE 1 TO CONDITIONS INCLUSIVE.
SWITCH  DO (0:3)
INTEGER  R, S, T
RECORD (TRAP) NAME  PLOT
!
PLOT == WHEN ACTION (N)
-> DO (PLOT_CLASS)
    !
    !
DO (0):; ! NO SPECIFIC TRAP.
    ! DON'T STOP ON USER RESULT NON-ZERO, NOR IF WE ARE ON-LINE.
    IF  N#1 AND  ONLINE=0 THEN  START 
        PRINT STRING ("**** Job terminated")
        NEWLINE
        SSOWN_STATE = 10
    FINISH 
    -> XND
    !
DO (1):; ! .GOTO TRAP.
    PRINT STRING ("**** Fault trap: .GOTO ".STRING(PLOT_ADDRESS))
    NEWLINE
    DESTINATION = STRING (PLOT_ADDRESS)
    IF  LENGTH(DESTINATION)>13 C 
    THEN  LABEL PROMPT = SUBSTRING (DESTINATION,1,13).":?" C 
    ELSE  LABEL PROMPT = DESTINATION.":?"
    SSOWN_LAST PROMPT = -1
    SSOWN_STATE = 2
    FOR  N=1,1,CONDITIONS CYCLE 
        PLOT == WHEN ACTION (N)
        IF  PLOT_CLASS=1 C 
        AND  STRING(PLOT_ADDRESS)=DESTINATION C 
        THEN  START 
            PLOT_CLASS = 0
            PLOT_BOUND = 0
            PLOT_ADDRESS = 0
        FINISH 
    REPEAT 
    -> XND
    !
DO (2):; ! CALL TRAP.
    PRINT STRING ("**** Fault trap: call ".STRING(PLOT_ADDRESS))
    NEWLINE
    DO CALL (STRING(PLOT_ADDRESS), C 
        STRING(PLOT_ADDRESS+BYTE INTEGER(PLOT_ADDRESS)+1), C 
        R, S, T)
    IF  R#0 THEN  START 
        PRINT STRING ("**** Trap fails! - ".STRING(ADDR(WTX(WNDX(R)))))
        NEWLINE
        UNLESS  18#R#19 THEN  PRINT ERRORS (S, MACRO ETEXTS)
    FINISH 
    -> XND
    !
DO (3):; ! START-FINISH TRAP.
    PRINT STRING ("**** Fault trap:")
    NEWLINE
    NEW LEVEL (PLOT_BOUND, PLOT_ADDRESS, 0, R)
    IF  R#0 THEN  START 
        PRINT STRING ("**** Too many input levels: cannot trap fault")
        NEWLINE
    FINISH 
    !
XND:
!
END 
!
INTEGER  FN  EVAL
! RESULT SHOULD BE ZERO FOR FALSE, NON-ZERO FOR TRUE.
INTEGER  B, L, I, TEST, N, C, VAL, VARIABLE
INTEGER  SGN, D, CLASS
SWITCH  PROC (1:6)
CONST  BYTE  INTEGER  ARRAY  ESS (1:4,1:4) = C 
     5,  5,  2,  5,
     3,  3,  6,  6,
     4,  4,  6,  6,
     6,  1,  6,  6
STRING  (255) S, T
STRING  (2) PAD
CONST  STRING  (3) LEG = "<=>"
CONST  STRING  (2) EG = "=>"
STRING  (5) TVT
B = 0
SYNTAX RESULT = 0
!
! AT THE END OF THIS ROUTINE, 'SYNTAX RESULT' WILL HAVE BITS SET TO INDICATE
! ERRORS AS FOLLOWS:
!     1 - "BRACKETS OR QUOTES IN PREDICATE"
!     2 - "PREDICATE MISSING"
!     4 - "UNRECOGNISED NAME IN PREDICATE"
!     8 - "INVALID COMPARATOR"
!    16 - "INVALID INTEGER"
!    32 - "LOGICAL INSTEAD OF INTEGER"
!    64 - "INTEGER INSTEAD OF LOGICAL"
!
IF  LENGTH(PRED)=0 C 
THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000002' C 
ELSE  START 
    S = PURGE (PRED, PFLAGS, L); ! NOW S HAS NO SPACES.
    IF  L<=LENGTH(PRED) C 
    THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000001'
    !
    ! **** **** MACHINE CODE FOR THIS NEXT BIT? **** ****
    I = 1
    WHILE  I<=LENGTH(S) AND  'A'<=BYTE INTEGER(ADDR(S)+I)<='Z' CYCLE 
        I = I + 1
    REPEAT 
    ! **** **** END OF MACHINE CODE SECTION **** ****
    !
    IF  I#1 THEN  START 
        T = SUBSTRING (S, 1, I-1)
        N = RECOGNISE IDENTIFIER (T)
    FINISH  ELSE  N = 0
    IF  N=0 THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000004'
    IF  I<=LENGTH(S) THEN  START 
        ! LOOK FOR COMPARATOR:
        TEST = 6
        ! **** **** A COUPLE OF RESOLUTIONS IN THE NEXT **** ****
        ! **** **** FEW LINES ARE UNNECESSARILY ELABORATE. **** ****
        ! **** **** SOME SIMPLE MACHINE CODE COULD DO THE **** ****
        ! **** **** REQUIRED TESTS EASILY. **** ****
        IF  LEG->PAD.(TOSTRING(BYTE INTEGER(ADDR(S)+I))) THEN  START 
            TEST = LENGTH (PAD)
            I = I + 1
            IF  TEST#1 C 
            AND  I<=LENGTH(S) C 
            AND  EG->PAD.(TOSTRING(BYTE INTEGER(ADDR(S)+I))) C 
            THEN  START 
                TEST = TEST + LENGTH (PAD) + 3
                I = I + 1
            FINISH 
        FINISH 
        !
        ! VALUES OF 'TEST' ARE:
        !   0 - <
        !   1 - =
        !   2 - >
        !   3 - <=
        !   4 - <>
        !   5 - >=
        !   6 - NO VALID COMPARATOR FOUND
        !
        IF  TEST=6 THEN  START 
            D = 2; ! DISCARDING TAIL OF COMPARATOR.
            SYNTAX RESULT = SYNTAX RESULT ! X'00000008'
        FINISH  ELSE  D = 1; ! EXPECTING SIGN OR DIGIT.
        VAL = 0
        SGN = +1
        WHILE  I<=LENGTH(S) CYCLE 
            C = BYTE INTEGER (ADDR(S) + I)
            IF  '0'<=C<='9' THEN  CLASS = 1 ELSE  START 
            IF  C='+' THEN  CLASS = 2 ELSE  START 
            IF  C='-' THEN  CLASS = 3 ELSE  CLASS = 4
            FINISH 
            FINISH 
            -> PROC(ESS(D,CLASS))
            !
PROC (6):   I = 1023; ! FORCES EXIT WITH I=1024 FOR 'INVALID INTEGER'.
            -> NEXT
            !
PROC (4):   SGN = -1
PROC (3):   D = 4; ! EXPECTING FIRST DIGIT.
            -> NEXT
            !
PROC (5):   D = 3; ! EXPECTING ANOTHER DIGIT.
PROC (2):   VAL = 10*VAL + C - '0'
PROC (1):
NEXT:
            I = I + 1
        REPEAT 
        IF  D#3 OR  I=1024 C 
        THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000010'
        IF  N>VARIABLES C 
        THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000020'
        IF  SYNTAX RESULT=0 THEN  START 
            VAL = SGN * VAL
            VARIABLE = VARS (N)
            !
            ! THIS NEXT BIT IS MERE BIT TWIDDLING, BUT IT IS COMPACT AND
            ! FAST, AND I ASSERT THAT IT GIVES B NON-ZERO IF AND ONLY IF
            ! THE RELATIONSHIP DEFINED BY 'TEST' HOLDS BETWEEN THE
            ! THE VARIABLE AND THE INTEGER VALUE.
            IF  VARIABLE=VAL THEN  B = TEST & 1 ELSE  START 
                IF  VARIABLE<VAL C 
                THEN  B = (TEST-1) & 2 C 
                ELSE  B = (5*(TEST-1)) & 4
            FINISH 
            !
        FINISH 
    FINISH  ELSE  START 
        IF  N#0 THEN  START 
            IF  N<=VARIABLES C 
            THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000040' C 
            ELSE  START 
                IF  N<COND LIM THEN  B = VARS (N-VARIABLES) ELSE  START 
                    BEGIN 
                    SWITCH  LOGIC (COND LIM:IDENTIFIERS)
                    -> LOGIC (N)
                    !
LOGIC (18):         B =   PROG FLAG C 
                        ! CMND FLAG %C
                        ! LOAD FLAG %C
                        ! JOB FLAG %C
                        ! FILE FLAG
                    -> LEX
                    !
LOGIC (19):         B = ONLINE
!                   -> LEX
!                   !
! LOGIC (??): !     B = -1; ! TRUE.
!                   -> LEX
!                   !
! LOGIC (??): !     B = 0; ! FALSE.
                    !
LEX:                END 
                FINISH 
            FINISH 
        FINISH 
    FINISH 
FINISH 
IF  B#0 THEN  TVT = "TRUE" ELSE  TVT = "FALSE"
PRINT STRING ("++++ Evaluating: """.PRED.""" yields ".TVT)
NEWLINE
! PRINT STRING ("                  ".PFLAGS)
! NEWLINE
IF  SYNTAX RESULT#0 THEN  SSOWN_WARNING NUMBER = 20
RESULT  = B
END 
!
IF  DIAGOP#0 THEN  START 
   ROUTINE  LIST TRAPS
   CONST  STRING  (20) ARRAY  CTXT (1:CONDITIONS) = C 
        "USER RESULT NON-ZERO",
        "PROGRAM FAULT",
        "COMMAND FAILURE",
        "LOAD FAILURE",
        "JCL ERROR",
        "FILE ERROR"
   INTEGER  B, I, J
   RECORD (TRAP) NAME  PROCEDURE
   SWITCH  T (1:3)
   FOR  I=1,1,CONDITIONS CYCLE 
       PRINT STRING ("TRAP FOR ".CTXT(I).": ")
       PROCEDURE == WHEN ACTION (I)
       B = PROCEDURE_BOUND & X'00FFFFFF'
       IF  B=0 THEN  PRINT STRING ("NONE") ELSE  START 
           -> T (PROCEDURE_CLASS)
           !
   T(1):  PRINT STRING (".GOTO ".STRING(PROCEDURE_ADDRESS))
           -> NEXT
           !
   T(2):  PRINT STRING ("CALL ".STRING(PROCEDURE_ADDRESS))
           -> NEXT
           !
   T(3):  PRINT STRING ("OBEY -".NLSTRING)
           FOR  J=0,1,B-1 CYCLE 
               PRINT SYMBOL (BYTE INTEGER(PROCEDURE_ADDRESS+J))
           REPEAT 
           PRINT STRING ("<< END OF TEXT")
           !
   NEXT:
       FINISH 
       NEWLINE
   REPEAT 
   END 
FINISH 
!
ROUTINE  SAVE BYTES (INTEGER  BOUND, ADDRESS, INTEGER  NAME  F)
! %INTEGER I; ! NOT NEEDED IF WE USE 'MOVE'.
F = 0
BOUND = BOUND & X'00FFFFFF'
IF  BOUND#0 THEN  START 
    IF  SSOWN_SAVE PTR+BOUND>=SSOWN_SAVE LIM C 
    THEN  F = X'00004000' C 
    ELSE  START 
        !
        ! **** **** THIS COULD BE REPLACED BY MACHINE CODE **** ****
        ! %FOR I=0,1,BOUND-1 %CYCLE
        !     BYTE INTEGER (SSOWN_SAVE PTR + I) = BYTE INTEGER (ADDRESS + I)
        ! %REPEAT
        ! EQUIVALENT TO:
        MOVE (BOUND, ADDRESS, SSOWN_SAVE PTR)
        ! **** **** END OF MACHINE CODE SECTION **** ****
        !
        SSOWN_SAVE PTR = SSOWN_SAVE PTR + BOUND
    FINISH 
FINISH 
END 
!
ROUTINE  SAVE COND (STRING  NAME  P, F, INTEGER  T)
STRING  (255) S
INTEGER  L, N
IF  DIAGOP#0 THEN  START 
    STRING  (8) TTXT
    IF  T=1 THEN  TTXT = ".GOTO" ELSE  START 
    IF  T=2 THEN  TTXT = "call" ELSE  START 
    IF  T=3 THEN  TTXT = "sequence" ELSE  TTXT = "T="
    FINISH 
    FINISH 
    PRINT STRING ("++++ Saving .WHENEVER """.P.""" with ".TTXT)
    UNLESS  1<=T<=3 THEN  PRINT (T,3,0)
    NEWLINE
    PRINT STRING ("                       ".F)
    NEWLINE
FINISH 
SYNTAX RESULT = 0
!
! AT THE END OF THIS ROUTINE, THE GLOBAL VARIABLE 'SYNTAX RESULT'
! WILL HAVE BITS SET TO INDICATE ERRORS AS FOLLOWS:
!     1 - "BRACKETS OR QUOTES IN PREDICATE"
!     2 - "PREDICATE MISSING"
!     4 - "UNRECOGNISED NAME IN PREDICATE"
!   128 - "PREDICATE INVALID FOR WHENEVER"
! IF 'SYNTAX RESULT' IS NOT ZERO ON EXIT, THEN 'SSOWN_WARNING NUMBER' WILL BE
! SET TO 20.
!
! CHECK THE PREDICATE:
IF  P="" THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000002' ELSE  START 
    S = PURGE (P, F, L)
    IF  L<=LENGTH(P) THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000001'
    N = RECOGNISE IDENTIFIER (S)
    IF  N=0 THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000004'
    UNLESS  VARIABLES<N<COND LIM C 
    OR  N=18 C 
    THEN  SYNTAX RESULT = SYNTAX RESULT ! X'00000080'
FINISH 
IF  SYNTAX RESULT=0 THEN  START 
    WHEN CONDITION = N - VARIABLES
    WHEN SPEC_CLASS = T
    WHEN SPEC_ADDRESS = SSOWN_SAVE PTR
FINISH  ELSE  START 
    SSOWN_WARNING NUMBER = 20
    WHEN CONDITION = 0
FINISH 
END 
!
ROUTINE  SAVE CALL IN SEQUENCE (STRING  NAME  C)
INTEGER  ERROR
IF  WHEN CONDITION=0 THEN  RETURN 
IF  DIAGOP#0 THEN  START 
    PRINT STRING ("++++ Saving call: """.C."""")
    NEWLINE
    PRINT STRING ("                   ".F)
    NEWLINE
FINISH 
IF  SSOWN_ACCUMULATING=0 THEN  START 
    SSOWN_ACCUMULATION_BOUND = 0
    SSOWN_ACCUMULATION_ADDRESS = SSOWN_SAVE PTR
    SSOWN_ACCUMULATING = -1
FINISH 
IF  SSOWN_ACCUMULATION_ADDRESS+SSOWN_ACCUMULATION_BOUND=SSOWN_SAVE PTR THEN  START 
    SAVE BYTES (LENGTH(C), ADDR(C)+1, ERROR)
    IF  ERROR=0 THEN  START 
        IF  SSOWN_SAVE PTR>=SSOWN_SAVE LIM C 
        THEN  ERROR = 1 C 
        ELSE  START 
            BYTE INTEGER (SSOWN_SAVE PTR) = NL
            SSOWN_SAVE PTR = SSOWN_SAVE PTR + 1
            SSOWN_ACCUMULATION_BOUND = SSOWN_ACCUMULATION_BOUND + LENGTH (C) + 1
        FINISH 
    FINISH 
    IF  ERROR#0 THEN  START 
        SSOWN_ACCUMULATION_ADDRESS = 0
    FINISH 
FINISH  ELSE  ERROR = 1
IF  ERROR#0 THEN  SSOWN_WARNING NUMBER = 21
END 
!
!
ROUTINE  SAVE STRINGS (STRING  NAME  C, F)
INTEGER  ERROR
IF  WHEN CONDITION=0 THEN  RETURN 
IF  DIAGOP#0 THEN  START 
    PRINT STRING ("++++ Saving: """.C."""")
    NEWLINE
    PRINT STRING ("              ".F)
    NEWLINE
FINISH 
SAVE BYTES (LENGTH(C)+1, ADDR(C), ERROR)
IF  ERROR=0 THEN  SAVE BYTES (LENGTH(F)+1, ADDR(F), ERROR)
IF  ERROR#0 THEN  SSOWN_WARNING NUMBER = 21 ELSE  START 
    WHEN SPEC_BOUND = LENGTH (C) + 1
    STOW WHEN ACTION; ! WHAT IF THIS COULD FAIL?
FINISH 
END 
!
ROUTINE  STOW WHEN ACTION
INTEGER  W
! **** **** WHAT IF WHEN CONDITION=0 ? **** ****
IF  WHEN CONDITION<=CONDITIONS C 
THEN  WHEN ACTION (WHEN CONDITION) = WHEN SPEC C 
ELSE  START 
    IF  WHEN CONDITION=18-VARIABLES THEN  START 
        FOR  W=2,1,CONDITIONS CYCLE 
            WHEN ACTION (W) = WHEN SPEC
        REPEAT 
    FINISH 
FINISH 
END 
!
ROUTINE  DEAL WITH MACRO C 
    (INTEGER  NAME  Q, STRING  NAME  OPENDATA, CLOSEDATA)
!
! ON EXIT FROM THIS ROUTINE, Q WILL BE ZERO IF IT HAS WORKED
! SUCCESSFULLY.  OTHERWISE, BITS WILL BE SET IN Q TO INDICATE
! FAILURES.
!   X'00000001' - KEYWORD MISSING IN DECLARATION
!   X'00000004' - TOO MANY PARAMETER FIELDS IN DECLARATION
!   X'00000400' - MACRO WORK AREA TOO FULL
!   X'00000800' - CANNOT RECOGNISE MACRO HEADER
!   X'00001000' - TOO MANY INPUT LEVELS
!   X'00002000' - MACRO DECLARATION IGNORED - NO TEXT
!   X'00004000' - WORK SPACE EXHAUSTED - DECLARATION FAILS
!   X'00008000' - NAMELESS MACRO
!   X'00010000' - TOO MANY MACROS
!
STRING  (255) ROUTINE NAME
STRING  (1) DUMMY
PROMPT ("Text:")
SSOWN_LAST PROMPT = -1
GATHER DATA (CLOSEDATA, 3)
IF  SSOWN_ACCUMULATION_ADDRESS=0 THEN  START 
    Q = X'00004000'
    RETURN 
FINISH 
DISCARD DATA HEADER (OPENDATA)
IF  SSOWN_ACCUMULATION_BOUND&X'00FFFFFF'=0 THEN  START 
    Q = X'00002000'
    RETURN 
FINISH 
! **** **** FOR TESTING ONLY **** ****
IF  DIAGOP#0 THEN  START 
    BEGIN 
        INTEGER  J
        PRINT STRING ("Accumulated text:")
        NEWLINE
        FOR  J=1,1,SSOWN_ACCUMULATION_BOUND&X'00FFFFFF' CYCLE 
            PRINT SYMBOL (BYTE INTEGER(SSOWN_ACCUMULATION_ADDRESS+J-1))
        REPEAT 
        PRINT STRING ("<< End of text")
        NEWLINE
    END 
FINISH 
! **** **** END OF TESTING CODE **** ****
EXAMINE MACRO C 
    (ROUTINE NAME,DUMMY,SSOWN_ACCUMULATION_BOUND,SSOWN_ACCUMULATION_ADDRESS,0,Q)
IF  Q#0 THEN  RETURN 
IF  ROUTINE NAME="" THEN  START 
    Q = X'00008000'
    RETURN 
FINISH 
IF  KNOWN MACS>=MAC LIMIT THEN  START 
    Q = X'00010000'
    RETURN 
FINISH 
! **** **** TESTING **** ****
PRINT STRING ("++++ Declaring macro ".ROUTINE NAME.NLSTRING)
! **** **** ENDS **** ****
KNOWN MACS = KNOWN MACS + 1
MAC TEXT (KNOWN MACS) = SSOWN_ACCUMULATION
SSOWN_ACCUMULATION_ADDRESS = SSOWN_SAVE PTR
SAVE BYTES (LENGTH(ROUTINE NAME), ADDR(ROUTINE NAME)+1, Q)
IF  Q=0 THEN  START 
    SSOWN_ACCUMULATION_BOUND = LENGTH (ROUTINE NAME) ! X'18000000'
    MAC NAME (KNOWN MACS) = SSOWN_ACCUMULATION
FINISH  ELSE  START 
    KNOWN MACS = KNOWN MACS - 1
FINISH 
END 
!
ROUTINE  DO CALL (STRING  NAME  C, F, INTEGER  NAME  WF, FM, TRB)
INTEGER  MN, A, B, J, L, NP, PF
STRING  (255) ROUTINE NAME, PARMS, PARM TEXT
STRING  (255) ARRAY  DATALIM (1:2)
STRING  (4) ARRAY  KF (1:2)
RECORD (PD) ARRAY  PVAL (1:2)
RECORD (FRF) FR
CONST  INTEGER  SS CHAR FILE TYPE = 3
!
!
ROUTINE  SDELIM (STRING  (64) MACPARM)
INTEGER  L, B, J
APARAM (MACPARM, PARMS, 2, KF, 4, PVAL, NP, PF)
DATALIM (1) = SSOWN_D DELIM 1
DATALIM (2) = SSOWN_D DELIM 2
IF  PF#0 OR  NP#2 THEN  START 
    ! **** **** WHAT SHOULD WE DO HERE? **** ****
FINISH  ELSE  START 
    J = 1
    WHILE  J<=2 CYCLE 
        L = PVAL(J)_BOUND & X'00FFFFFF'
        B = PVAL(J)_ADDRESS
        IF  J=L=1 AND  BYTE INTEGER(B)='*' THEN  START 
            J = 3; ! FORCE EXIT WITH DELIMITERS UNCHANGED.
        FINISH  ELSE  START 
            IF  L#0 THEN  COPY TO STRING (PVAL(J), DATALIM(J))
        FINISH 
        J = J + 1
    REPEAT 
FINISH 
END 
PARMS = ""
TRB = 0
WF = 0
IF  SSOWN_BRACKET FLAG=0 C 
THEN  ANALYSE CALL N (C,F,ROUTINE NAME,PARMS,WF) C 
ELSE  ANALYSE CALL B (C,F,ROUTINE NAME,PARMS,WF)
IF  WF#0 THEN  START 
    IF  DIAGOP#0 THEN  START 
        PRINT STRING ("++++ Executing: """.C."""")
        NEWLINE
        PRINT STRING ("                 ".F)
        NEWLINE
    FINISH 
FINISH  ELSE  START 
    UNLESS  CTU#ROUTINE NAME#"" THEN  START 
        IF  DIAGOP#0 THEN  START 
            PRINT STRING ("++++ Null call")
            NEWLINE
        FINISH 
        -> CALL DONE
    FINISH 
    IF  DIAGOP#0 THEN  START 
        IF  ROUTINE NAME=".?W" THEN  START 
            LIST TRAPS
            -> CALL DONE
        FINISH 
    FINISH 
    IF  ROUTINE NAME=".MACRO" THEN  START 
        SDELIM ("FROM=.MACBEGIN,TO=.MACEND")
        DEAL WITH MACRO (FM, DATALIM(1), DATALIM (2))
        IF  FM#0 THEN  START 
            WF = 18
        FINISH 
        -> CALL DONE
    FINISH 
    !
    IF  ROUTINE NAME=".LOCATE" THEN  START 
        PARM TEXT = "FILE"
        APARAM  C 
            (PARM TEXT, PARMS, 1, KF, 4, PVAL, NP, CMND FLAG)
        IF  CMND FLAG#0 THEN  WF = 22 ELSE  START 
            COPY TO STRING (PVAL(1), PARM TEXT)
            IF  ULCEQUIV#0 THEN  START 
                UCTRANSLATE (ADDR(PARM TEXT)+1, LENGTH(PARM TEXT))
            FINISH 
            FINFO (PARM TEXT, 0, FR, RETURN CODE)
            FILE FLAG = RETURN CODE
            PRINT STRING ("++++ File ".PARM TEXT)
            IF  FILE FLAG=0 C 
            THEN  PRINT STRING (" exists") C 
            ELSE  START 
                PRINT STRING (" does not exist")
                TRB = TRB ! X'00000001'
            FINISH 
            NEWLINE
        FINISH 
        -> CALL DONE
    FINISH 
    !
    IF  ROUTINE NAME=".INPUT" THEN  START 
        BEGIN 
        INTEGER  DL, FILE BASE
        RECORD (PD) DD
        RECORD (HF) NAME  FILE HEADER
        PARM TEXT = "FILE"
        APARAM C 
            (PARM TEXT, PARMS, 1, KF, 4, PVAL, NP, CMND FLAG)
        IF  CMND FLAG#0 THEN  WF = 22 ELSE  START 
            SUPPLY DATA DESCRIPTOR (DD)
            COPY TO STRING (PVAL(1), PARM TEXT)
            IF  ULCEQUIV#0 THEN  START 
                UCTRANSLATE (ADDR(PARM TEXT)+1, LENGTH(PARM TEXT))
            FINISH 
            FINFO (PARM TEXT, 0, FR, PF)
            IF  PF=0 THEN  START 
                ! FILE ALREADY EXISTS.
                PRINT STRING ("**** File already exists")
                NEWLINE
                CMND FLAG = -1
                TRB = TRB ! X'00000004'
            FINISH  ELSE  START 
                DL = DD_BOUND & X'00FFFFFF'
                OUTFILE (PARM TEXT, DL+32, 0, 0, FILE BASE, CMND FLAG)
                IF  CMND FLAG#0 THEN  START 
                    PRINT STRING ("**** Cannot create file")
                    NEWLINE
                    TRB = TRB ! X'00000004'
                FINISH  ELSE  START 
                    FILE HEADER == RECORD (FILE BASE)
                    FILE HEADER_DATA END = DL + 32
                    FILE HEADER_DATA START = 32
                    FILE HEADER_FILE TYPE = SS CHAR FILE TYPE
                    MOVE (DL, DD_ADDRESS, FILE BASE+32)
                    DISCONNECT (PARM TEXT, PF)
                FINISH 
            FINISH 
        FINISH 
        END 
        -> CALL DONE
    FINISH 
    !
    IF  ROUTINE NAME=".DELIMITERS" THEN  START 
        SDELIM ("FROM=.DATA,TO=.ED")
        SSOWN_D DELIM 1 = DATALIM (1)
        SSOWN_D DELIM 2 = DATALIM (2)
        -> CALL DONE
    FINISH 
    IF  ROUTINE NAME=".SAVERESULT" THEN  START 
        PARM TEXT = "SAVE=A"
        APARAM (PARM TEXT,PARMS,1,KF,4,PVAL,NP,CMND FLAG)
        IF  CMND FLAG#0 THEN  WF = 22 ELSE  START 
            COPY TO STRING (PVAL(1),PARM TEXT)
            IF  ULCEQUIV#0 THEN  START 
                UCTRANSLATE (ADDR(PARM TEXT)+1, LENGTH(PARM TEXT))
            FINISH 
            IF  STARTSWITH(PARM TEXT,"RESULT",-1)#0 THEN  START 
            FINISH 
            PF = 0
            IF  LENGTH(PARM TEXT)=1 C 
            THEN  PF = BYTE INTEGER (ADDR(PARM TEXT)+1) - 'A' + 7
            IF  7<=PF<=10 C 
            THEN  VARS (PF) = RETURN CODE C 
            ELSE  WF = 22
        FINISH 
        -> CALL DONE
    FINISH 
    IF  ROUTINE NAME=".ENDJOB" THEN  START 
        SSOWN_STATE = 10
        -> CALL DONE
    FINISH 
    IF  DIAGOP#0 THEN  START 
        PRINT STRING ("++++ Routine: """.ROUTINE NAME)
        IF  PARMS="" C 
        THEN  PRINT STRING (""" with no parameters") C 
        ELSE  PRINT STRING (""", parameters: """.PARMS."""")
        NEWLINE
    FINISH 
    L = LENGTH (ROUTINE NAME)
    IF  BYTE INTEGER(ADDR(ROUTINE NAME)+1)='#' THEN  START 
        HASH COMMAND (SUBSTRING(ROUTINE NAME,2,L), PARMS)
        AFTER COMMAND
        -> CALL DONE
    FINISH 
    IF  KNOWN MACS>0 THEN  START 
        A = ADDR (ROUTINE NAME)
        FOR  MN = KNOWN MACS,-1,1 CYCLE 
            IF  MAC NAME(MN)_BOUND&X'00FFFFFF'=L THEN  START 
                B = MAC NAME(MN)_ADDRESS - 1
                !
                ! **** **** USE MACHINE CODE FOR THIS: **** ****
                J = 1
                WHILE  J<=L C 
                AND  BYTE INTEGER(A+J)=BYTE INTEGER(B+J) C 
                CYCLE 
                    J = J + 1
                REPEAT 
                ! **** **** END OF MACHINE CODE SECTION **** ****
                !
                IF  J>L THEN  START 
                    EXAMINE MACRO (ROUTINE NAME,PARMS, C 
                        MAC TEXT(MN)_BOUND,MAC TEXT(MN)_ADDRESS, C 
                        -1,FM)
                    IF  FM#0 THEN  START 
                        WF = 19
                    FINISH 
                    -> CALL DONE
                FINISH 
            FINISH 
        REPEAT 
    FINISH 
    !
    BEGIN 
    INTEGER  BOUND LOADED, ADDRESS LOADED, TYPE LOADED
   LONGINTEGERNAME  DESC
    ! CALL LOADER.
   DESC==LONGINTEGER(ADDR(BOUND LOADED))
    IF  L<=31  THEN  START 
      IF  NEWLOADER=0 THEN  LOAD COMMAND (ROUTINE NAME, ROUTINE NAME, C 
           TYPE LOADED, BOUND LOADED, ADDRESS LOADED, LOAD FLAG) C 
       ELSE  START 
         TYPE LOADED=CODE!MACRO
         DESC=LOADEP(ROUTINENAME,TYPELOADED,LOADFLAG,SSOWN_LOADLEVEL)
         ! For consistency in this module TYPELOADED should be 1 for
         ! 'system commands'
         IF  LOADFLAG=0 AND  TYPELOADED=CODE AND  C 
         INTEGER(ADDRESS LOADED+4)<SSOWN_SSCURBGLA THEN  TYPELOADED=1
      FINISH 
   FINISH  ELSE  LOAD FLAG = 1
    ! PUT RESULT CODE IN 'LOAD FLAG'.
    ! SET UP 'TYPE LOADED', ETC.
    IF  LOAD FLAG#0 THEN  START 
        PRINT STRING ("**** Failed to load ".ROUTINE NAME.NLSTRING)
        TRB = TRB ! X'00000008'
    FINISH  ELSE  START 
        IF  TYPE LOADED=4 THEN  START 
            EXAMINE MACRO (ROUTINE NAME,PARMS, C 
                BOUND LOADED,ADDRESS LOADED,-1,FM)
            IF  FM#0 THEN  START 
                WF = 19
            FINISH 
        FINISH  ELSE  START 
            ! **** **** TEMPORARY BODGE TO DEAL WITH 'RUN' **** ****
            UNLESS  "OBEY"#ROUTINE NAME#"RUN" THEN  TYPE LOADED = 2
            ! **** **** END OF TEMPORARY BODGE **** ****
            IF  TYPE LOADED=1 THEN  CMND FLAG = 0 ELSE  RETURN CODE = 0
            PROG FLAG = 0
        !   FILE FLAG = 0
            ! ENTER CODE
            PROMPT ("Data:")
            SSOWN_LAST PROMPT = -1
            BEFORE COMMAND
! Set up the CLI strings SSOWN_CLICOMM and SSOWN_CLIPARM so that user progs can
! interrogate them with %systemstringfns CLICOMMAND and CLIPARAM
            SSOWN_CLICOMM=ROUTINE NAME
            SSOWN_CLIPARM=PARMS
            COMREG (24) = 0
            IF  ULCEQUIV=0 THEN  START 
                CLOSE UP (PARMS)
            FINISH  ELSE  START 
                CAST OUT (PARMS)
            FINISH 
            ENTER (2, BOUND LOADED, ADDRESS LOADED, PARMS)
            ! TIDY UP AFTER EXIT
            AFTER COMMAND
            ! PUT RESULTS INTO THE
            ! APPROPRIATE VARIABLES
            PROG FLAG = COMREG (10)
            IF  TYPE LOADED=1 THEN  START 
                CMND FLAG = COMREG (24) 
                IF  CMND FLAG#0 THEN  TRB = TRB ! X'00000004'
            FINISH  ELSE  START 
                RETURN CODE = COMREG (24)
                NEWLINE
                IF  RETURN CODE#0 THEN  START 
                    PRINT STRING ("++++ Result code =")
                    WRITE (RETURN CODE,3)
                    NEWLINE
                    TRB = TRB ! X'00000001'
                FINISH 
            FINISH 
            IF  PROG FLAG#0 THEN  START 
                TRB = TRB ! X'00000002'
            FINISH 
        !   %IF FILE FLAG#0 %THEN %START
        !       TRB = TRB ! X'00000020'
        !   %FINISH
        FINISH 
    FINISH 
    END 
    !
CALL DONE:
FINISH 
END 
!
!
ROUTINE  RESTORE VALUES
SSOWN_STATE = OUTER STATE
SSOWN_WARNING NUMBER = OUTER WARNING
SSOWN_BRACKET FLAG = LAST BRACKET FLAG
SSOWN_D DELIM 1 = OLD D1
SSOWN_D DELIM 2 = OLD D2
END 
!
!
END 
!
! AFTER THE %END %OF %FILE, THIS FILE ACTUALLY CONTAINS
! FURTHER TEXT! VIZ, THE ORIGINAL VERSION OF 'GET STMT'
! IN CASE IT IS NEEDED FOR REFERENCE.
!
END  OF  FILE 
!
! HERE FOLLOWS THE 'COMPACT' VERSION OF THE MAIN SWITCH IN
! THE INTERPRETER.
ACTION (2):
    UNLESS  0#TAKE ELSE#1 THEN  WARNING NUMBER = 2
ACTION (3):
ACTION (16):
    GATHER DATA (D DELIM 2, 1)
    -> ACT DONE
!
ACTION (45):
    ! TIDY ACCUMULATION (0)
    ACCUMULATING = 0
    ACCUMULATION_BOUND = ACCUMULATION_BOUND ! X'18000000'
    -> SET CLOSE
ACTION (4):
ACTION (37):
    IF  STMT="" THEN  WARNING NUMBER = 5
ACTION (17):
ACTION (25):
SET CLOSE:
    STATE = 10; ! CLOSING DOWN
    -> ACT DONE
!
ACTION (6):
    TAKE ELSE = 0
ACTION (38):
    DO CALL (CALL,CFLAGS,WARNING NUMBER,SYNTAX RESULT,TRAP BITS)
    -> ACT DONE
!
ACTION (8):
    COND = EVAL
    IF  COND=0 THEN  -> REJECT ELSE
ACTION (7):
    DESTINATION = PURGE (DEST,DFLAGS,REMPTR)
    IF  REMPTR<=LENGTH(DEST) OR  DESTINATION="" OR  DESTINATION="-" C 
    THEN  WARNING NUMBER = 17 C 
    ELSE  START 
        IF  BYTE INTEGER(ADDR(DESTINATION)+1)='-' THEN  START 
            GO BACK
            DESTINATION = C 
                SUBSTRING (DESTINATION, 2, LENGTH(DESTINATION))
        FINISH 
        STATE = 2; ! SCANNING FOR LABEL
    FINISH 
    -> REJECT ELSE
!
ACTION (9):
    COND = EVAL
    IF  COND#0 THEN  START 
        DO CALL (CALL,CFLAGS,WARNING NUMBER,SYNTAX RESULT,TRAP BITS)
        TAKE ELSE = 1
    FINISH  ELSE  TAKE ELSE = 2
    -> ACT DONE
!
ACTION (10):
    COND = EVAL
    LAST STATE = STATE
    IF  COND#0 THEN  STATE = 4 ELSE  STATE = 3
    ! OBEY FIRST HALF OR SKIP TO SECOND HALF
    -> ACT DONE
!
ACTION (11):
    IF  TAKE ELSE#1 THEN  START 
        IF  TAKE ELSE=2 C 
        THEN  DO CALL C 
            (CALL,CFLAGS,WARNING NUMBER,SYNTAX RESULT,TRAP BITS) C 
        ELSE  WARNING NUMBER = 7
        -> REJECT ELSE
    FINISH  ELSE  TAKE ELSE = 3
    -> ACT DONE
!
ACTION (13):
    TAKE ELSE = 0
ACTION (40):
    DESTINATION = PURGE (DEST,DFLAGS,REMPTR)
    IF  REMPTR<=LENGTH(DEST) C 
    OR  DESTINATION="" C 
    OR  BYTE INTEGER(ADDR(DESTINATION)+1)='-' C 
    THEN  WARNING NUMBER = 17 C 
    ELSE  START 
        SAVE COND (PRED,PFLAGS,1)
        IF  WARNING NUMBER=0 THEN  SAVE STRINGS (DESTINATION,NULLSTRING)
    FINISH 
    -> ACT DONE
!
ACTION (14):
    TAKE ELSE = 0
ACTION (41):
    SAVE COND (PRED,PFLAGS,2)
    IF  WARNING NUMBER=0 THEN  SAVE STRINGS (CALL,CFLAGS)
    -> ACT DONE
!
ACTION (15):
    TAKE ELSE = 0
ACTION (42):
    SAVE COND (PRED,PFLAGS,3)
    IF  WARNING NUMBER=0 THEN  START 
        STATE BEFORE WHEN = STATE
        STATE = 9; ! ACCUMULATING WHENEVER TEXT
    FINISH 
    -> ACT DONE
!
ACTION (19):
    TAKE ELSE = 1
    -> ACT DONE
!
ACTION (20):
    LAST STATE = STATE
    STATE = 7; ! SKIPPING TO .FINISH
    -> ACT DONE
!
ACTION (21):
    IF  TAKE ELSE#0 THEN  -> REJECT ELSE
    WARNING NUMBER = 7
    -> ACT DONE
!
ACTION (22):
ACTION (34):
    LAST STATE = STATE
    STATE = 8; ! SKIPPING OVER .WHENEVER
    -> ACT DONE
!
ACTION (29):
    STATE = 6
    -> FLAGACT
ACTION (30):
    STATE = 5
FLAG ACT:
    IF  CALL#"" THEN  WARNING NUMBER = 11
    -> ACT DONE
!
ACTION (32):
    STATE = 1
    -> REJECT ELSE
!
ACTION (33):
    STATE = LAST STATE
    -> REJECT ELSE
!
ACTION (44):
ACTION (43):
    GATHER DATA (D DELIM 2, 2)
    -> ACT DONE
!
ACTION (46):
    SAVE CALL IN SEQUENCE (CALL)
    -> ACT DONE
!
ACTION (47):
    ACCUMULATING = 0
    WHEN SPEC_BOUND = SAVE PTR - WHEN SPEC_ADDRESS
    STOW WHEN ACTION
    STATE = STATE BEFORE WHEN
ACTION (1):
ACTION (5):
ACTION (12):
ACTION (18):
REJECT ELSE:
    TAKE ELSE = 0
ACTION (23):
ACTION (26):
ACTION (27):
ACTION (28):
ACTION (31):
ACTION (39):
ACTION (48):
ACT DONE:
! HERE ENDS THE 'COMPACT' VERSION OF THE MAIN SWITCH IN
! THE INTERPRETER.
!
! HERE FOLLOWS THE OLD SWITCH-DRIVEN VERSION OF 'GET STMT':
! IT DOES NOT DEAL WITH THE 'CANCEL' PARAMETER.
ROUTINE  SPEC  GET STMT C 
   (INTEGER  BRACKET OPTION, C 
    INTEGER  QUOTE CONTRACTION, C 
    INTEGER  COMM, C 
    STRING  (80) D DELIM 1, C 
    STRING  (80) CONT, C 
    STRING  NAME  INPUT, C 
    STRING  NAME  RECON, C 
    STRING  NAME  MARKS, C 
    INTEGER  NAME  RESULT)
ROUTINE  GET STMT C 
   (INTEGER  BRACKET OPTION, C 
    INTEGER  QUOTE CONTRACTION, C 
    INTEGER  COMM, C 
    STRING  (80) D DELIM 1, C 
    STRING  (80) CONT, C 
    STRING  NAME  INPUT, C 
    STRING  NAME  RECON, C 
    STRING  NAME  MARKS, C 
    INTEGER  NAME  RESULT)
!
! THIS ROUTINE READS A COMPLETE STATEMENT VIA 'MASTER CHAR IN'
! (I.E., THROUGH THE MACRO EXPANSION PROCESS WHEN APPROPRIATE).
! THE UNPROCESSED TEXT WILL BE COPIED INTO THE STRING 'INPUT'.
! THE LAST CHARACTER READ WILL ALWAYS BE A NEWLINE (OR END-OF-FILE)
! UNLESS THE TEXT OVERFLOWS 'INPUT', IN WHICH CASE READING STOPS
! AT THAT POINT.
! THE TEXT AFTER RECONSTRUCTION IS PUT INTO 'RECON'.  RECONSTRUCTION
! MEANS THAT -
! EACH COMMENT IS REPLACED BY A SINGLE SPACE.
! QUOTES ARE PROPERLY MATCHED, SO THAT A NEWLINE IN QUOTES DOES NOT
! TERMINATE A STATEMENT.  NO LINE RECONSTRUCTION IS APPLIED TO TEXT
! IN QUOTES (EXCEPT TRAILING SPACE DELETION).
! IF THE 'BRACKETS' OPTION IS USED, BRACKETS ARE PROPERLY MATCHED, AND
! A NEWLINE WITHIN BRACKETS DOES NOT TERMINATE THE STATEMENT.  IT IS
! REPLACED BY A SINGLE SPACE, AND THE TEXT FROM THE NEXT LINE IS
! PROCESSED AS PART OF THE STATEMENT.
! WHERE A LINE ENDS WITH THE CONTINUATION MARKER, ALL CHARACTERS FROM
! THE MARKER TO THE NEWLINE ARE REPLACED BY A SINGLE SPACE, AND
! THE TEXT FROM THE NEXT LINE IS PROCESSED AS PART OF THE STATEMENT.
! THE TERMINATING NEWLINE OR END-OF-FILE CHARACTER WILL HAVE BEEN
! REMOVED, AND THE TEXT WILL HAVE NO LEADING OR TRAILING SPACES.
! ALL MULTIPLE SPACES, EXCEPT IN QUOTES, ARE REPLACED BY SINGLE SPACES.
!
! BRACKET OPTION=0 MEANS 'ASSUME NOBRACKETS'
!               #0 MEANS 'ASSUME BRACKETS OPTION'.
! QUOTE CONTRACTION#0 MEANS 'REDUCE "" TO " IF ALREADY IN QUOTES'
!                  =0 MEANS DON'T.
! COMM IS THE (SINGLE BYTE) COMMENT SYMBOL.
! D DELIM 1 IS THE OPENING DATA DELIMITER.
! CONT IS THE CONTINUATION MARKER.
! RAW TEXT WILL BE PUT INTO 'INPUT'.
! TEXT AFTER LINE RECONSTRUCTION WILL BE PUT INTO 'RECON'.
! CORRESPONDING TO EACH BYTE IN 'RECON' WILL BE ONE BYTE IN THE SAME
! POSITION IN 'MARKS'.
! 'MARKS' WILL GET:
!                     IN PLAIN TEXT       IN BRACKETS
! SPACE OR NEWLINE         A                   B
! TEXT                     C                   D
! TEXT IN QUOTES           E                   F
!
! THE OUTER BRACKETS (AND OF COURSE INNER BRACKETS ALSO)
! IN A SEQUENCE OF TEXT-IN-BRACKETS GET THE FLAG 'D'.
! THE OUTER QUOTES IN A SEQUENCE OF TEXT-IN-QUOTES GET THE
! FLAG 'E', OR 'F' IF IN BRACKETS.
!
! THE MAXIMUM LENGTH OF THE STRINGS INPUT, RECON AND MARKS MUST BE 255.
!
! RESULT WILL GET A VALUE TO INDICATE THE SUCCESS OR FAILURE OF
! GET STMT, AS FOLLOWS:
! RESULT = 0: O.K.
! RESULT = 1: OPENING DATA DELIMITER FOUND.
! RESULT = 2: INCOMPLETE STATEMENT BEFORE DATA DELIMITER.
! RESULT = 3: INCOMPLETE STATEMENT BEFORE END OF FILE.
! RESULT = 4: STATEMENT TOO LONG.
! RESULT = -1: PARAMETERS UNACCEPTABLE.
!
!
SWITCH  HANDLE (7:48)
INTEGER  C, D, CSW, STATE, LEADING SPACES SEEN, LAST TERMINATOR
INTEGER  INPUT CHAR ADDR, RECON CHAR ADDR, BRACKET LEVEL
INTEGER  PARMS OK, SWAC
! INPUT GETS AN UNRECONSTRUCTED COPY OF THE TEXT READ IN.
    ! STATES ARE -
    !   1: START OF LINE.
    !   2: PLAIN TEXT.
    !   3: PLAIN AFTER SPACE.
    !   4: IN QUOTES.
    !   5: IN COMMENT.
    !   6: AFTER CLOSING QUOTE.
    !
    ! N.B. START-OF-LINE IS NOT NECESSARILY START-OF-STATEMENT.  IN
    !   PARTICULAR, THE LINE MAY NOT BEGIN IN THE FIRST CHARACTER OF
    !   THE STRING, AND 'BRACKET LEVEL' MAY BE NON-ZERO AT
    !   START-OF-LINE.
    !
    ! PLAIN-AFTER-SPACE IS DIVIDED INTO TWO SUB-STATES.  IF THE SPACE
    !   WAS A SPACE IN THE INPUT TEXT, THEN 'SWAC=0'.  IF THE SPACE
    !   REPLACED SOME DISCARDED CHARACTER, THEN 'SWAC#0'.
    !
    ! COMMENT IS DIVIDED INTO TWO SUB-STATES: COMMENT-AT-START-OF-LINE
    !   IS DISTINGUISHED FROM COMMENT BY
    !   'RECON CHAR ADDR=LAST TERMINATOR'.
    !
    ! CHECK PARAMETERS:
    PARMS OK = -1; ! TRUE.
    BEGIN 
        STRING  (255) C1, C2
        IF  CONT="" C 
        OR  D DELIM 1="" C 
        OR  COMM=' ' C 
        OR  COMM='"' C 
        OR  CONT->C1.(TOSTRING(COMM)).C2 C 
        OR  CONT->C1.(" ").C2 C 
        OR  CONT->C1.("""").C2 C 
        OR  D DELIM 1->C1.(TOSTRING(COMM)).C2 C 
        OR  D DELIM 1->C1.(" ").C2 C 
        OR  D DELIM 1->C1.("""").C2 C 
        OR  D DELIM 1->C1.(CONT).C2 C 
        OR  CONT->C1.(D DELIM 1).C2 C 
        THEN  PARMS OK = 0; ! FALSE.
    END 
    IF  PARMS OK=0 THEN  START 
        RESULT = -1
        RETURN 
    FINISH 
    !
    STATE = 1; ! START OF STATEMENT.
    LEADING SPACES SEEN = 0; ! FALSE.
    INPUT = ""
    RECON = ""
    MARKS = ""
    LAST TERMINATOR = 0
    INPUT CHAR ADDR = 0
    RECON CHAR ADDR = 0
    BRACKET LEVEL = 0
    -> IN C; ! TO READ THE FIRST CHARACTER OF THE STATEMENT.
    !
HANDLE (42): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 0 - NEWLINE FOUND.
LINE END:
    UNLESS  BRACKET OPTION#0#BRACKET LEVEL THEN  START 
        ! STATEMENT COMPLETE.
        RESULT = 0
        -> TIDY UP
    FINISH 
    ! WE HAVE NOT YET COME TO END OF STATEMENT.
    STATE = 1; ! CARRY ON TO NEXT LINE IN "START-OF-LINE MODE".
INSERT TERMINATOR:
    C = ' '; ! USE A SPACE FOR THE LINE TERMINATOR.
STRING TERMINATOR:
    LEADING SPACES SEEN = 0
    LAST TERMINATOR = RECON CHAR ADDR + 1; ! I.E., WHERE THE
    ! TERMINATOR SYMBOL WILL BE PUT IN THE RECONSTRUCTED LINE.
    ! CARRY ON TO INSERT THE CHARACTER -
HANDLE (20): ! STATE 2 - PLAIN TEXT.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
HANDLE (30): ! STATE 4 - IN QUOTES.
             ! CSW 2 - COMMENT SYMBOL FOUND.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
HANDLE (31): ! STATE 4 - IN QUOTES.
             ! CSW 3 - SPACE FOUND.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
HANDLE (32): ! STATE 4 - IN QUOTES.
             ! CSW 4 - OPEN BRACKET FOUND.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
HANDLE (33): ! STATE 4 - IN QUOTES.
             ! CSW 5 - CLOSE BRACKET FOUND.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
HANDLE (34): ! STATE 4 - IN QUOTES.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
             ! INSERT CHAR IN RECONSTRUCTED LINE.
INSERT:      ! PUT CHARACTER IN RECONSTRUCTED LINE.
             ! FIRST DECIDE WHAT CHARACTER TO PUT IN 'MARKS'.
             UNLESS  4#STATE#6 THEN  D = 'E' ELSE  START 
                 UNLESS  ' '#C#NL THEN  D = 'A' ELSE  START 
                     IF  C=')' AND  BRACKET LEVEL=0 C 
                     AND  RECON CHAR ADDR>0 C 
                     AND  C 
                     (BYTE INTEGER(ADDR(MARKS)+RECON CHAR ADDR)-'A') C 
                     &1#0 C 
                     THEN  D = 'D' C 
                     ELSE  D = 'C'
                 FINISH 
             FINISH 
             IF  BRACKET LEVEL>0 THEN  D = D + 1
             !
             RECON CHAR ADDR = RECON CHAR ADDR + 1
             IF  RECON CHAR ADDR>255 THEN  -> L O L
             BYTE INTEGER (ADDR(RECON)+RECON CHAR ADDR) = C
             BYTE INTEGER (ADDR(MARKS)+RECON CHAR ADDR) = D
             LENGTH (RECON) = RECON CHAR ADDR
             LENGTH (MARKS) = RECON CHAR ADDR
HANDLE (24): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 3 - SPACE FOUND.
             ! NO ACTION.
HANDLE (36): ! STATE 5 - IN COMMENT.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
             ! NO ACTION.
HANDLE (38): ! STATE 5 - IN COMMENT.
             ! CSW 3 - SPACE FOUND.
             ! NO ACTION.
HANDLE (39): ! STATE 5 - IN COMMENT.
             ! CSW 4 - OPEN BRACKET FOUND.
             ! NO ACTION.
HANDLE (40): ! STATE 5 - IN COMMENT.
             ! CSW 5 - CLOSE BRACKET FOUND.
             ! NO ACTION.
HANDLE (41): ! STATE 5 - IN COMMENT.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
             ! NO ACTION.
IN C:        ! READ IN NEXT CHARACTER.
    C = MASTER CHAR IN (1)
    IF  C=25 THEN  -> E O F
    ! APPEND INPUT CHARACTER ONTO INPUT STRING.
    INPUT CHAR ADDR = INPUT CHAR ADDR + 1
    IF  INPUT CHAR ADDR>255 THEN  -> L O L
    BYTE INTEGER (ADDR(INPUT)+INPUT CHAR ADDR) = C
    LENGTH (INPUT) = INPUT CHAR ADDR
    ! DISTINGUISH VARIOUS INTERESTING CHARACTERS.
    IF  C=NL THEN  CSW = 0 ELSE  START 
    IF  C='"' THEN  CSW = 1 ELSE  START 
    IF  C=COMM THEN  CSW = 2 ELSE  START 
    IF  C=' ' THEN  CSW = 3 ELSE  START 
    IF  C='(' THEN  CSW = 4 ELSE  START 
    IF  C=')' THEN  CSW = 5 ELSE  START 
        CSW = 6
    FINISH 
    FINISH 
    FINISH 
    FINISH 
    FINISH 
    FINISH 
    ! CSW IS 0 FOR A NEWLINE,
    !        1 FOR A DOUBLE-QUOTE,
    !        2 FOR A COMMENT SYMBOL,
    !        3 FOR A SPACE,
    !        4 FOR AN OPEN BRACKET,
    !        5 FOR A CLOSING BRACKET,
    !        6 FOR ANY OTHER CHARACTER.
    !
    -> HANDLE (STATE*7 + CSW); ! SWITCH TO PROCESS INPUT CHARACTER.
    !
HANDLE (7):  ! STATE 1 - START OF STATEMENT.
             ! CSW 0 - NEWLINE FOUND.
             LEADING SPACES SEEN = 0
             -> IN C
             !
HANDLE (43): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
             IF  QUOTE CONTRACTION#0 THEN  START 
                 STATE = 4; ! NOW IN QUOTES AGAIN.
                 -> IN C; ! PUT NOTHING IN THE RECONSTRUCTED LINE -
                 ! JUST GO AND GET THE NEXT CHARACTER.
             FINISH 
HANDLE (8):  ! STATE 1 - START OF STATEMENT.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
HANDLE (15): ! STATE 2 - PLAIN TEXT.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
HANDLE (22): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
             STATE = 4; ! NOW IN QUOTES.
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (9):  ! STATE 1 - START OF STATEMENT.
             ! CSW 2 - COMMENT SYMBOL FOUND.
             LEADING SPACES SEEN = -1; ! TRUE -
             ! TREAT THE COMMENT LIKE A SPACE.
HANDLE (23): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 2 - COMMENT SYMBOL FOUND.
             STATE = 5; ! NOW IN COMMENT.
             -> IN C; ! DON'T PUT THIS CHARACTER IN THE RECONSTRUCTED
             ! LINE: JUST GO AND GET THE NEXT ONE.
             !
HANDLE (10): ! STATE 1 - START OF STATEMENT.
             ! CSW 3 - SPACE FOUND.
             LEADING SPACES SEEN = -1; ! TRUE.
             -> IN C; ! HAVING REMEMBERED THAT WE'VE SEEN THIS
             ! CHARACTER, WE IGNORE IT AND GET THE NEXT ONE.
             !
HANDLE (11): ! STATE 1 - START OF STATEMENT.
             ! CSW 4 - OPEN BRACKET FOUND.
HANDLE (25): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 4 - OPEN BRACKET FOUND.
HANDLE (46): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 4 - OPEN BRACKET FOUND.
             STATE = 2; ! NOW IN PLAIN TEXT.
HANDLE (18): ! STATE 2 - PLAIN TEXT.
             ! CSW 4 - OPEN BRACKET FOUND.
             ! REMEMBER THE OPEN BRACKET:
             BRACKET LEVEL = BRACKET LEVEL + 1
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (12): ! STATE 1 - START OF STATEMENT.
             ! CSW 5 - CLOSE BRACKET FOUND.
HANDLE (26): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 5 - CLOSE BRACKET FOUND.
HANDLE (47): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 5 - CLOSE BRACKET FOUND.
             STATE = 2; ! NOW IN PLAIN TEXT.
HANDLE (19): ! STATE 2 - PLAIN TEXT.
             ! CSW 5 - CLOSE BRACKET FOUND.
             ! REMEMBER THE CLOSE BRACKET:
             IF  BRACKET LEVEL>0 THEN  BRACKET LEVEL = BRACKET LEVEL - 1
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (13): ! STATE 1 - START OF STATEMENT.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
HANDLE (27): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
HANDLE (48): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 6 - NOT A SPECIAL CHARACTER.
             STATE = 2; ! NOW IN PLAIN TEXT.
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (16): ! STATE 2 - PLAIN TEXT.
             ! CSW 2 - COMMENT SYMBOL FOUND.
HANDLE (44): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 2 - COMMENT SYMBOL FOUND.
             STATE = 5; ! NOW IN COMMENT.
             C = ' '; ! SUBSTITUTE A SPACE IN THE RECONSTRUCTED LINE.
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (21): ! STATE 3 - PLAIN AFTER SPACE.
             ! CSW 0 - NEWLINE FOUND.
             ! DISCARD TRAILING SPACES (THERE WILL BE EXACTLY ONE).
             RECON CHAR ADDR = RECON CHAR ADDR - 1
             LENGTH (RECON) = RECON CHAR ADDR
             IF  SWAC#0 THEN  -> LINE END
HANDLE (14): ! STATE 2 - PLAIN TEXT.
             ! CSW 0 - NEWLINE FOUND.
             ! THERE ARE NO TRAILING SPACES WHEN WE GET HERE.
             IF  LEADING SPACES SEEN=0 C 
             AND  SUBSTRING(RECON,LAST TERMINATOR+1, C 
                 RECON CHAR ADDR)=D DELIM 1 C 
             THEN  START 
                 IF  LAST TERMINATOR=0 THEN  -> D D FOUND ELSE  -> I C S
             FINISH 
             ! NEXT WE CHECK WHETHER THE LINE ENDS WITH
             ! A CONTINUATION MARKER.
             IF  RECON CHAR ADDR>=LENGTH(CONT) C 
             AND  SUBSTRING(RECON,RECON CHAR ADDR-LENGTH(CONT)+1, C 
                 RECON CHAR ADDR)=CONT C 
             THEN  START 
                 ! DISCARD THE CONTINUATION MARKER, AND
                 ! ADJUST RECON CHAR ADDR.
                 RECON CHAR ADDR = RECON CHAR ADDR - LENGTH (CONT)
                 LENGTH (RECON) = RECON CHAR ADDR
                 STATE = 1; LEADING SPACES SEEN = 0
                 ! IF THE LINE DOES NOT END WITH A SPACE (NOW THAT THE
                 ! CONTINUATION MARKER HAS BEEN REMOVED), WE PUT THE
                 ! SPACE IN.
                 IF  RECON CHAR ADDR>0 C 
                 AND  NL#BYTEINTEGER(ADDR(RECON)+RECON CHAR ADDR)#' ' C 
                 THEN  START 
                     LAST TERMINATOR = RECON CHAR ADDR + 1
                     C = ' '
                     -> INSERT
                 FINISH 
                 ! LAST CHARACTER WAS A SPACE, SO WE DON'T INSERT ANOTHER.
                 LAST TERMINATOR = RECON CHAR ADDR
                 -> IN C
             FINISH 
             -> LINE END
             !
HANDLE (17): ! STATE 2 - PLAIN TEXT.
             ! CSW 3 - SPACE FOUND.
HANDLE (45): ! STATE 6 - AFTER CLOSING QUOTE.
             ! CSW 3 - SPACE FOUND.
             STATE = 3; SWAC = 0; ! NOW IN PLAIN-AFTER-SPACE.
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (28): ! STATE 4 - IN QUOTES.
             ! CSW 0 - NEWLINE FOUND.
             ! THERE MAY BE SEVERAL TRAILING SPACES (OR NONE) TO DISCARD.
             WHILE  BYTE INTEGER(ADDR(RECON)+RECON CHAR ADDR)=' ' CYCLE 
                 RECON CHAR ADDR = RECON CHAR ADDR - 1
             REPEAT 
             LENGTH (RECON) = RECON CHAR ADDR
             ! WE COULD NOT BE 'IN QUOTES' IF THE FIRST LINE OF THE
             ! STATEMENT WERE AN OPENING DATA DELIMITER, SO WE ONLY
             ! TEST SUBSEQUENT LINES.
             IF  LAST TERMINATOR#0 C 
             AND  RECON CHAR ADDR>LAST TERMINATOR C 
             AND  SUBSTRING(RECON,LAST TERMINATOR+1, C 
                 RECON CHAR ADDR)=D DELIM 1 C 
             THEN  -> I C S; ! INCOMPLETE STATEMENT FOUND BEFORE DELIMITER.
             -> STRING TERMINATOR
             !
HANDLE (29): ! STATE 4 - IN QUOTES.
             ! CSW 1 - DOUBLE-QUOTE FOUND.
             STATE = 6; ! AFTER CLOSING QUOTE.
             -> INSERT; ! PUT THE CHARACTER IN THE RECONSTRUCTED LINE.
             !
HANDLE (35): ! STATE 5 - IN COMMENT.
             ! CSW 0 - NEWLINE FOUND.
             ! THERE MAY BE ONE TRAILING SPACE OR NONE.
             IF  RECON CHAR ADDR=LAST TERMINATOR THEN  START 
                 ! THIS STATE - COMMENT WITH RECON CHAR ADDR=LAST TERMINATOR -
                 ! IS ACTUALLY DISTINCT FROM ALL THE OTHERS, BUT
                 ! THE DISTINCTION IS SO RARELY SIGNIFICANT (I.E.,
                 ! NOWHERE ELSE BUT HERE AND AT HANDLE(37)) THAT
                 ! NO SPECIFIC STATE NUMBER HAS BEEN ALLOCATED.
                 !
                 ! WE ARE AT THE END OF A COMMENT WHICH STARTED ON THE
                 ! FIRST CHARACTER OF THE RECONSTRUCTED LINE, SO THAT IT
                 ! HAS NOT BEEN REPLACED BY A SINGLE SPACE,
                 ! AND WE HAVE ONLY TO RESET THE CONDITIONS FOR
                 ! START-OF-STATEMENT AND GO ON TO THE NEXT LINE.
                 STATE = 1; ! START OF STATEMENT.
                 LEADING SPACES SEEN = 0
                 -> IN C
             FINISH  ELSE  START 
                 ! WE ARE IN A COMMENT WHICH STARTED AFTER THE
                 ! START OF STATEMENT.  THERE WILL BE
                 ! A SINGLE TRAILING SPACE TO DELETE.
                 RECON CHAR ADDR = RECON CHAR ADDR - 1
                 LENGTH (RECON) = RECON CHAR ADDR
                 ! RECON CHAR ADDR CANNOT BE ZERO HERE.
                 -> LINE END
             FINISH 
             !
HANDLE (37): ! STATE 5 - IN COMMENT.
             ! CSW 2 - COMMENT SYMBOL FOUND.
             IF  RECON CHAR ADDR=LAST TERMINATOR THEN  START 
                 STATE = 1
             FINISH  ELSE  START 
                 STATE = 3
                 SWAC = -1
             FINISH 
             ! NOW IN PLAIN-AFTER-SPACE UNLESS WE HAVE JUST SEEN THE END
             ! OF A COMMENT WHICH STARTED AT THE BEGINNING OF THE
             ! RECONSTRUCTED LINE, IN WHICH CASE WE REVERT TO
             ! START-OF-STATEMENT.
             -> IN C; ! PUT NOTHING IN THE RECONSTRUCTED LINE -
             ! JUST GO AND GET THE NEXT CHARACTER.
             !
L O L: ! LINE TOO LONG.
    WHILE  NL#C#25 CYCLE 
        C = MASTER CHAR IN (1)
    REPEAT 
    RESULT = 4
    -> TIDY UP
    !
E O F: ! INCOMPLETE STATEMENT FOUND BEFORE END-OF-FILE.
    RESULT = 3
    -> TIDY UP
    !
I C S: ! INCOMPLETE STATEMENT FOUND BEFORE OPENING DATA DELIMITER.
    RESULT = 2
    -> TIDY UP
    !
D D FOUND: ! OPENING DATA DELIMITER FOUND.
    RESULT = 1
    !
TIDY UP:
    LENGTH (MARKS) = RECON CHAR ADDR
    RETURN 
    !
END