! Modified   22/November/83   12.00








!----------Conditional Compilation Constants:
                !
                !
          CONSTINTEGER    EMAS= 0
          CONSTINTEGER    VME = 1

          CONSTINTEGER  SYSTEM= EMAS




SYSTEMROUTINE    FDIAG  (INTEGER       OLD LNB, PCOUNT ,
                         INTEGER       MODE   ,  DIAG  ,  ASIZE ,
                         INTEGERNAME   FIRST  , NEW LNB)
                         !
                         !
                         !
!
!*********************************************************************%C
!*********************************************************************%C
                                                                      C 
                                                                      C 
     a PROCEDURE common to FORTRAN(G), FORTRAN(J), and FORTRAN77      C 
                                                                      C 
           which provides diagnostic information pertaining to a      C 
                                                                      C 
           single FORTRAN code component                              C 
                                                    (version 3.0)     C 
                                                         --IMP80      C 
!*********************************************************************%C
!*********************************************************************%C
                                                                      !
                                                                      !
              !it takes over the function performed by S#FDIAG   1/2/78
              !it takes over the function performed by S#FIO1    1/3/81
              !it takes over the function performed by S#FIO2    1/3/81





!The Parameters have the following uses:
                !                                                     %C
                OLD LNB  ptr to the stack of the failing routine      C 
                PCOUNT   PC at the point of failure                   C 
                MODE     set as: 0=> EMAS or JOBBER
                               ! 1=> VME and error is not software detected
                               ! 2=> VME and error is software detected
!               DIAG     diagnostic level control variable            %C
                ASIZE    number of array elements to output           C 
                FIRST    variable to be set to one if this            C 
                                  is the 1st call on FDIAG            C 
                NEW LNB  variable to be set at exit to the            C 
                                  address of the next stack frame



!History:                                                                     %C
                                                                              C 
          FDIAG12 upgraded to handle subprograms which were                   C 
                  compiled using the option OPT3.                             C 
                                                                              C 
          FDIAG10 modified from FDIAG8 replacing OWN variables into local     C 
                  name space so that FDIAG can be linked within the           C 
                 'System Gla' sharing EMAS subsystem.




RECORDFORMAT  SYMBOL TABLE HEADER        (                            C 
                                                                      C 
            INTEGER        LINE NO DISP  ,
            INTEGER        OPTIONS       ,
            INTEGER        SUBPROG TYPE  ,
                                                                      C 
{OPT3 Only}(INTEGER   NEXT SYMTABS       ,   {OPT3 Only}
{OPT3 Only} INTEGER  FIRST PCOUNT        ,   {OPT3 Only}
{OPT3 Only} INTEGER    PTR TO RETURN ADDR,   {OPT3 Only}
                                                                      C 
             STRING (32)   SUBPROG NAME  OR  STRING (32) SUBPROG ID))


RECORD  (Symbol Table Header) NAME  S,T



RECORDFORMAT  FORM OF GLA       (                                     C 
                                                                      C 
     INTEGER              Word0 ,
     INTEGER              Word1 ,
     INTEGER          GST ADDR  ,
     INTEGER      SYMTABS BASE  ,
     INTEGER              FLAGS ,
     INTEGERARRAY         WORDS (5:17)      ,
                                                                      C 
     INTEGER         CODE BASE  {at GLA+72} )


RECORD  (Form of GLA) NAME  GLA






!
!***********************************************************************
!
!     SPECIFICATIONS FOR MAIN UTILITY ROUTINES
!
!***********************************************************************
!
  ROUTINESPEC  PHEX                (INTEGER    VALUE            )
  ROUTINESPEC  DUMP                (INTEGER    START,FINISH     )
  ROUTINESPEC  SORT AND PRINT NAMES(INTEGER  SYMTABS,NO OF NAMES)
INTEGERFNSPEC  LINE NO FROM PCOUNT




!***********************************************************************
!
!     CONSTANTS
!
!***********************************************************************

CONSTINTEGER         DOT   =  '.'
CONSTINTEGER  EBCDIC ZERO  = C'0'
CONSTINTEGER         PLUS  =  '+'
CONSTINTEGER         QUOTE =  ''''
CONSTINTEGER         MINUS =  '-'
CONSTINTEGER         NOUGHT=  '0'
!*
!*
!*
CONSTINTEGER    NONE   = 0
CONSTINTEGER    NOT SET= 0
CONSTINTEGER    NIL    = 0
CONSTINTEGER    FALSE  = 0
CONSTINTEGER    TRUE   = 1
                         !Values taken by 'boolean' variables
                         !            (ie. Integers used as flags)


!
!   Descriptors
!
CONSTINTEGER  STRING DESC= X'58000000'
CONSTINTEGER    BYTE DESC= X'19000000'; !(bound check inhibited)
                !
                !these constants represent the basic form of          %C
                                 a descriptor for accessing           C 
                                 a string of bytes.



!
!   Floating Point Constants
!
CONSTLONGLONGREAL    POINT ONE   = R'40199999999999993299999999999999'
CONSTLONGLONGREAL   TEN TO THE 11= R'4A174876E80000003C00000000000000'
CONSTLONGLONGREAL   TEN TO THE 12= R'4AE8D4A5100000003C00000000000000'
CONSTLONGLONGREAL   TEN TO THE 75= R'7F235FADD81C282271BB3F07877973CC'
CONSTLONGLONGREAL   TEN TO THE                                        C 
                         MINUS 75= R'0273CAC65C39C96174615B058E891876'


CONSTINTEGER  OUTPUT LEN= 120; !The record length -1 of the diagnostic
                               !    stream. Should the characteristics
                               !    of the stream change then only this
                               !    variable need be altered.



!
!   Types of FORTRAN Procedures
!
CONSTSTRING (13) ARRAY    SUBPROG TYPES(1:3)= "MAIN PROGRAM " ,
                                              "FUNCTION "     ,
                                              "SUBROUTINE "

CONSTSTRING (10) ARRAY   FUNCTION TYPES(1:5)= "INTEGER " , "REAL "    ,
                                              "COMPLEX " , "LOGICAL " ,
                                              "CHARACTER "


!Texts of FORTRAN77, FORTRAN(G), and FORTRAN(J):
       !
       CONSTSTRING (11) ARRAY   COMPILER(0:2)= "FORTRAN77 "  ,
                                               "FORTRAN(G) " ,
                                               "FORTRAN(J) "





!***********************************************************************
!
!     GLOBAL VARIABLES
!
!***********************************************************************
!

!
!   Address of an External Workarea
!
INTEGER  DESC OF EXTERNAL AREA
INTEGER  ADDR OF EXTERNAL AREA
              !
              !address of a large (>32771 bytes) area which may be used
              !         for long  (>256 bytes) CHARACTER values (F77 only)
                                                                     !%C
NOTE:
    !for EMAS    EXTERNAL AREA NAME= "T#FIOAREA"
    !for VME                       =   "FIOAREA"
           !
           !and  EXTERNAL AREA SIZE=      33792 bytes

!
!   Addresses of Internal Data Areas
!
INTEGER  GLA ADDR         ; !GLA address of failing routine
INTEGER  GST ADDR         ; !Address of the Array Area
INTEGER  BASE             ; !Base address of local variables


!
!   Pointers to the Symbol Tables
!
INTEGER  ADR SYMTABS; !ptr to the start of the Symbol Tables for current module
INTEGER  CUR SYMTABS; !ptr to the start of the Symbol Tables for current procedure
INTEGER      SYMTABS; !ptr through the Symbol Tables for the current procedure

INTEGER  PTR TO NEXT TABLE; !ptr to start of (next) set of Common Block records

!
!   Variables associated with the failing line number
!
INTEGER  LINE NO TABLE  ; !=1 if PC/Line No Mapping Table given
INTEGER  LINE NO DISP   ; !>0 if line number is somewhere
INTEGER  LINE NO        ; !the failing line number
       !
       !The failing line number is located in one of three ways:
            !RELEASE 55 and later:
            !        BYTES 10-11 of the symbol tables set to the stack
            !        displacement of the line number.
            !        BYTES  4- 7 set to the displacement from GLA of
            !        the PC/line number mapping table if present.
            !
            !RELEASE 50 and earlier:
            !        Bit 1 in BYTE 8 set if a PC/line number mapping
            !        table is to be used to extract the line number.
            !        It is located at GLA + (BYTES 4-7) of symbol tables
            !        Otherwise BYTES 4-7 contain the displacement of the
            !        line number on the stack.

!
!   Values set in the Symbol Table Header
!
INTEGER      OPTIONS   ; !copy of the language dependent bits
INTEGER      VERSION   ; !set to indicate the FORTRAN version
                             !as follows:
                            constinteger  F77= 0,
                                          FG = 1,
                                          FJ = 2
INTEGER      DEBUG FLAG; !set +ve if PARM(DEBUG) was specified, or
                         !set +ve if ITS code is included     , else= 0
INTEGER       OPT3 FLAG; !set +ve if PARM(OPT3) was specified, else= 0
INTEGER     EBCDIC MODE; !set +ve if PARM(EBCDIC) was specified, else= 0
INTEGER    SUBPROG TYPE; !set to indicate the type of FORTRAN procedure
                             !as follows:
                                        ! =1 =>Main Program
                                        ! =2 =>Function
                                        ! =3 =>Subroutine
INTEGER  NAME CNT GIVEN; !set +ve if Symbol Table includes a count
                         !        of the number of identifier names
INTEGER     NO OF NAMES; !number of Local identifiers or Common identifiers

INTEGER                                                               C 
        ITEMS OFF STACK; !In RELEASE 70 and later, there may be no
                         !   Initialised Stack, but rather an external
                         !   area whose use and appearence is similar
                         !   to an Initialised Stack
                         !                                            %C
        ITEMS OFF STACK= false if this is not the case                C 
        ITEMS OFF STACK> zero  if there is no Initialised Stack

!
!   Utility Variables
!
INTEGER  STATE     ; !set as follows:
                        !=-1 =>Local variables  to be/being printed
                        != 0 =>Common variables to be printed
                        != 1 =>Common variables being printed
INTEGER    PTR     ; !scanning pointer through the identifier records
INTEGER    I,J     ; !work variables
INTEGER    USER LNB; !address of the stack frame (copied from 1st parameter)
INTEGER  STRING LEN; !length of the procedure's name

!
!   Local Variables which could be OWNs
!
STRING (12) NOT ASSIGNED TEXT
              ! assigned value "NOT ASSIGNED" and used
              !   when a value is not assigned

INTEGER  BAD CHAR BYTES   ; !assigned   4
INTEGER  BAD DESC OF PARM ; !assigned X'18000004'
INTEGER  BAD ADDR OF PARM ; !assigned  -1
INTEGER  BAD NUM  OF ITEMS; !assigned   0
                  !                                                   %C
     The area above is used as an alternative descriptor/dope vector  C 
     when a REF(NAME) parameter is undefined and triggers a trap in   C 
     the routine PRINT NAME.


IF  SYSTEM= VME THENSTART 
        !
        !   VME String Variables
        !
        OWNSTRING (32)  MODULE NAME; !name of the procedure
        OWNSTRING (51) SUBPROG NAME; !descriptive text of the procedure

FINISHELSESTART 
    !
    !   EMAS String Variables
    !
    STRING (32)  MODULE NAME; !name of the procedure
    STRING (51) SUBPROG NAME; !descriptive text of the procedure
           !
           !
          FINISH ; !if EMAS


   {Inhibit Floating Point Underflow:}  *MPSR_  X'40C0'

!Get the GLA address
         !
         OLD LNB= OLD LNB & X'FFFFFFFC'
        USER LNB= OLD LNB AND  GLA ADDR= INTEGER(USER LNB+16)

                  GLA== RECORD(GLA ADDR)

!
!   Determine if there is an Initialised Stack  (Items On Stack=Yes)
!
    ITEMS OFF STACK = GLA_FLAGS & 2
IF  ITEMS OFF STACK¬= FALSE THEN  OLD LNB= INTEGER(USER LNB+12)
                            !
                            !NOTE that if items are off stack then any
                            !     such items will be in a pseudo-stack
                            !     which has the same appearence as a
                            !     static stack frame.
!
!   INITIALISE VARIABLES
!
    SYMTABS= INTEGER(OLD LNB + 12) & X'FFFFFF'
          !=displacement of Symbol Tables from the start of the Table Area
IF  SYMTABS=NOT SET THENSTART 
              IF  DIAG<0 THEN         NEW LNB =-1                     C 
                         ELSESTART 
                             *STSF_  I
                                 J=  USER LNB + 256
                             IF  J>I THEN   J = I
                                 PRINT STRING("
SUBPROGRAM COMPILED WITHOUT DIAGNOSTICS

STACK FRAME
");                              DUMP (USER LNB , J)
                                        NEW LNB = INTEGER(USER LNB)
                             FINISH 
              RETURN 
              FINISH 

    GST ADDR= GLA_GST ADDR
    SYMTABS = GLA_SYMTABS BASE + SYMTABS
CUR SYMTABS =     SYMTABS

       !Note:     SYMTABS is a pointer which is moved through the current Symbol Tables
       !      CUR SYMTABS is a pointer to the start of the current Symbol Tables
       !      ADR SYMTABS is a pointer to the start of the module's Symbol Tables
              ADR SYMTABS= SYMTABS

                S== RECORD(SYMTABS)

!
!   PICK UP THE LANGUAGE DEPENDENT BITS
!
 OPTIONS        = S_OPTIONS
 EBCDIC MODE    =   OPTIONS & X'80000000' ; !set if PARM(EBCDIC)
 LINE NO  TABLE =   OPTIONS & X'40000000' ; !set if PARM(NOCHECK,NODIAG)
 NAME CNT GIVEN =   OPTIONS & X'20000000'
    DEBUG FLAG  =   OPTIONS & X'08000000'
     OPT3 FLAG  =   OPTIONS & X'01000000'

    IF  OPTIONS & X'02000000'> 0 THEN  VERSION= F77    ELSESTART 
    IF  OPTIONS & X'10000000'> 0 THEN  VERSION= FJ     C 
                                 ELSE  VERSION= FG;    FINISH 

IF  OPT3 FLAG¬=False THENSTART 
              !
       PCOUNT = PCOUNT - GLA_CODE BASE IF  MODE=0
    !
   {!}  Locate the Appropriate Symbol Tables:
    !
    IF  S_FIRST PCOUNT > PCOUNT THEN  CUR SYMTABS= ADR SYMTABS        C 
                                AND             S==RECORD(CUR SYMTABS)

A:  IF  S_NEXT SYMTABS= Not Set THENSTART 

              -> NEXT OPT3 PROC IF  S_SUBPROG TYPE=Not Set
                    !
                    ! Jump if PCOUNT points to 'Transfer Code'
                    !   ie if PCOUNT points to code which converts a
                    !            JLK into a call on an external procedure
             FINISHELSESTART 

        T== RECORD(S_NEXT SYMTABS + ADDR(S))
    IF  T_FIRST PCOUNT <  PCOUNT THEN  S==T AND  -> A
    FINISH 

            CUR SYMTABS=      ADDR(S)
                SYMTABS=      ADDR(S_SUBPROG NAME)
            MODULE NAME=           S_SUBPROG NAME

FINISHELSE  MODULE NAME=           S_SUBPROG ID                       C 
       AND      SYMTABS=      ADDR(S_SUBPROG ID)

    LINE NO DISP= S_LINE NO DISP & X'FFFF'
!
!   PICK UP THE LINE NUMBER (AT POINT OF FAILURE)
!
IF  DEBUG FLAG¬=FALSE AND  MODE=1 THEN  LINE NO=LINE NO FROM PCOUNT   C 
                                  ELSESTART 
    I= OPTIONS & X'FFFF'
IF  I> 0 THEN  LINE NO= INTEGER(OLD LNB + I)                          C 
         ELSESTART 
         IF  LINE NO TABLE¬=0 THEN  LINE NO= LINE NO FROM PCOUNT      C 
                              ELSESTART 
                              IF  LINE NO DISP=NOT SET                C 
                                 THEN  LINE NO=NOT SET                C 
                                 ELSE  LINE NO=INTEGER(OLD LNB        C 
                                                         + LINE NO DISP)
                                 FINISH 
         FINISH 
         FINISH 
    NEWLINE
IF  LINE NO<0 THEN  LINE NO= 0

!
!   COLLECT SUBPROGRAM TYPE (AND NAME)
!
     I          = S_SUBPROG TYPE
    SUBPROG TYPE=        I & X'FF'
    SUBPROG NAME=   SUBPROG TYPES (SUBPROG TYPE)
IF  SUBPROG TYPE>1 THENSTART 
                       SUBPROG NAME= SUBPROG NAME . MODULE NAME
                   IF  SUBPROG TYPE=2                                 C 
                      THEN  SUBPROG NAME= FUNCTION TYPES ((I>>8) & 15)C 
                                                        . SUBPROG NAME
                   FINISH 

IF  MODE=0 THENSTART 
!
!   PRINT 'DIAGNOSTICS ENTERED FROM .....' IF IN JOBBER OR EMAS MODE
!
IF  FIRST¬=FALSE THEN  FIRST=FALSE       AND                          C 
    PRINT STRING ("DIAGNOSTICS ")
    PRINT STRING ("ENTERED FROM ".SUBPROG NAME)
IF  LINE NO>0 THEN                                                    C 
    PRINT STRING ("  LINE ")  AND    WRITE(LINE NO,1)
FINISHELSESTART 

IF  DIAG<0 THENSTART 
!
!   PICK UP ROUTINE NAME AND LINE NUMBER FOR OPEH PRE-AMBLE
!
            FIRST  = ADDR(MODULE NAME)
            NEW LNB=      LINE NO
           RETURN 
           FINISH 
!
!         OR PRINT DIAGNOSTIC BLURB IF IN STAND-ALONE MODE
!
 PRINT STRING (COMPILER (VERSION) . SUBPROG NAME)
       !
       IF  MODE¬= 0 ANDC 
           DIAG = 1 ANDC 
          ASIZE¬= 0 THEN  PRINT STRING (" (MODULE ".STRING(ASIZE).")")

     IF  LINE NO> 0 THEN  PRINT STRING (" AT LINE ")                  C 
                    AND         WRITE  (LINE NO,1  )

IF  DIAG=1 THENSTART 
              NEWLINE

           UNLESS  OPT3 FLAG= False THENSTART 
               !
               !   Check for more Procedures to Report on in this Module
               !
               IF  S_PTR TO RETURN ADDR¬= Not Set THENSTART 

NEXT OPT3 PROC:
        J= INTEGER(S_PTR TO RETURN ADDR + OLD LNB) - 4
          {link address stored by current routine at entry - 4}

   PCOUNT= J - GLA_CODE BASE
          {relative displacement within the calling procedure}

        -> Locate the Appropriate Symbol Tables

       FINISH 
FINISH 
RETURN  {if DIAG=1}
FINISH 
FINISH 

!
!   POINT TO START OF LOCAL IDENTIFIER RECORDS
!
    STRING LEN= LENGTH(MODULE NAME)
IF  STRING LEN>15 THEN  STRING LEN= (STRING LEN + 4) & X'3C'          C 
                  ELSE  STRING LEN= 16
    SYMTABS = SYMTABS + STRING LEN
    SYMTABS = SYMTABS + 4  IF  NAME CNT GIVEN¬=FALSE; !skip around any
                                                      !   TOTAL ID COUNT
    BASE    = GLA ADDR; STATE= -1
                  !
                  ADDR OF EXTERNAL AREA= NOT SET

!Initialise 'Local OWN's
        !
        NOT ASSIGNED TEXT = "NOT ASSIGNED"

         BAD CHAR BYTES   =   4
         BAD DESC OF PARM = X'18000004'
         BAD ADDR OF PARM =  -1
         BAD NUM  OF ITEMS=   0
!
!   DETERMINE NUMBER OF LOCAL NAMES
!
NEXT SECTION:     IF  NAME CNT GIVEN=FALSE THENSTART 
!
     NO OF NAMES= NOT SET
     PTR        = SYMTABS
    CYCLE 
           I= INTEGER(PTR)
       IF  I=-1 OR  I=M'****' THEN  -> SORT
           NO OF NAMES= NO OF NAMES + 1
           PTR= (PTR + 8 + BYTEINTEGER(PTR+4)) & X'FFFFFFFC'
    REPEAT 
FINISHELSE  NO OF NAMES= INTEGER(SYMTABS)                             C 
      AND       SYMTABS=     4 + SYMTABS
!
!
!   SORT AND PRINT NAMES IN ALPHABETIC ORDER
!
!
SORT:    NEWLINE
!
IF  NO OF NAMES>0 THEN  SORT AND PRINT NAMES(SYMTABS,NO OF NAMES)     C 
                  ELSE  PTR TO NEXT TABLE =  SYMTABS

IF  DIAG>  3 THENSTART 
!
!   HANDLE A(NOTHER) COMMON BLOCK
!
IF  INTEGER(PTR TO NEXT TABLE)>0 THENSTART 
    SYMTABS     = PTR TO NEXT TABLE + 4
    BASE        = INTEGER(OLD LNB + INTEGER(SYMTABS))
    SUBPROG NAME= STRING(SYMTABS+4)
    SYMTABS     = (SYMTABS + 8 + BYTEINTEGER(SYMTABS+4)) & X'FFFFFFFC'
    STATE       = 0
               !=>a COMMON to be printed
    -> NEXT SECTION
FINISH ; FINISH 


 -> NEXT OPT3 PROC IF  OPT3 FLAG¬= False AND  S_PTR TO RETURN ADDR¬= Nil

!
!   Determine the next (earlier) stack frame
!
IF  SUBPROG TYPE=1 THENSTART ;                   ! MAIN PROGRAM
                            I=NONE
             FINISHELSESTART ;                   ! SUBROUTINE or FUNCTION
                            I=INTEGER(USER LNB)
                            I=INTEGER(I) IF  ITEMS OFF STACK=FALSE
                      FINISH 
                      !
       NEW LNB= I     ANDRETURN 



INTEGERFN  LINE NO FROM PCOUNT
!
!
!
!
!   THIS IS A LOCAL ROUTINE TO DETERMINE THE LINE NUMBER
!
!        FROM THE P-COUNTER AT THE POINT OF FAILURE WHEN
!
!        A STORE MAP HAS BEEN PROVIDED.
!
!
!
INTEGER  TABLE BEGIN; !Start address of Line Number Store Map Table
INTEGER  TABLE START; !Addr of first entry in Store Map Table (variable)
INTEGER  TABLE END  ; !Addr of last  entry in Store Map Table (variable)
INTEGER  MOD PCOUNT ; !PCOUNT adjusted to look like entries in Table
!
INTEGER  PTR; !Scanning pointer through Table
INTEGER  I,J; !Entries of Table currently under examination
INTEGER  PC ; !Relative PCOUNT from start of code
!
!   INITIALISE VARIABLES
!
 TABLE BEGIN=  CUR SYMTABS + LINE NO DISP
 TABLE END  = (INTEGER(TABLE BEGIN)<<2) + TABLE BEGIN
 TABLE START=  TABLE BEGIN + 4
IF  MODE=0 AND  OPT3 FLAG=False THEN  PCOUNT= PCOUNT - INTEGER(OLD LNB +20)
     PC    = PCOUNT & X'0003FFFF'
 MOD PCOUNT= PC    << 13
!
!   CHECK VALIDITY OF P-COUNTER
!
IF  MOD PCOUNT<=INTEGER(TABLE START) THENRESULT = 0
IF  MOD PCOUNT>=INTEGER(TABLE END) & X'7FFFE000'                      C 
       THEN  I= INTEGER(TABLE END) & X'1FFF' AND  -> CHECK LINE SIZE
 -> START SEARCH
!
!   SCAN TABLE USING A BINARY SEARCH PATTERN
!
LOOP:
!
    I= INTEGER(PTR)
IF  I<MOD PCOUNT THENSTART 
                  TABLE START= PTR + 4
                  J          = INTEGER(TABLE START)
              IF  J>MOD PCOUNT THENSTART 
                       IF  J&X'7FFFE000'<MOD PCOUNT THEN  ->LINE IN J C 
                                                    ELSE  ->LINE IN I
                       FINISH 
START SEARCH:     PTR= TABLE START + ((((TABLE END - TABLE START)>>1) C 
                                                   + 3) & X'FFFFFFFC')
                  -> LOOP
                 FINISH 

IF  I>MOD PCOUNT THENSTART 
                  TABLE END= PTR - 4
                  J        = INTEGER(TABLE END)
              IF  J<MOD PCOUNT THENSTART 
                       IF  I&X'7FFFE000'>MOD PCOUNT THEN  ->LINE IN J C 
                                                    ELSE  ->LINE IN I
                       FINISH 
                  PTR= TABLE END - ((((TABLE END - TABLE START) >> 1) C 
                                                 + 3) & X'FFFFFFFC' )
                  -> LOOP
                 FINISH 
LINE IN I:   I= I & X'1FFF'; -> CHECK LINE SIZE
LINE IN J:   I= J & X'1FFF'
!
!   TEST IF THE CAPABILITY EXISTS TO MAP LINE NUMBERS > 8192
!
CHECK LINE SIZE:
      !
      IF  S_OPTIONS&X'04000000'>0 THENSTART 
          !
          !   ADD ON LINE NUMBERING BASE
          !
              I= I + INTEGER(TABLE BEGIN-4)
          FINISH 
RESULT =I
END ; !of LINE NO FROM PCOUNT





ROUTINE  SORT AND PRINT NAMES(INTEGER  SYMTABS,NO OF NAMES)
!
!
!
!
!     A routine to construct a list of addresses of
!
!           the variable names, and then to sort the
!
!           names into alphabetic order. Each name
!
!           is then printed.
!
!
!
INTEGERFNSPEC  ARRAY ADDRESS1 (INTEGER  DV ADDR)
INTEGERFNSPEC  ARRAY ADDRESS2 (INTEGER  DV ADDR)
  ROUTINESPEC  PRINT NAME     (STRINGNAME  NAME)
  ROUTINESPEC    SET NAME
!
INTEGERARRAY  ADDRESS(1:NO OF NAMES)
              !
              !Each entry in this array is to be set to the address
              !     of each variable name. These entries will then
              !     be sorted, so that the names appear in
              !     alphabetic order.
              !
!
!   Control Variables
!
INTEGER  DEFAULT DV TYPE; !set to 0 if array descriptors generally
                                   !address the 1st actual element
                          ! or +ve if  array descriptors generally
                                   !address the zero'th element
INTEGER     NAME CNT    ; !cycle control variable through
                          !      the identifier records
!
!   Variables used for sorting the variable names
!
INTEGER  MIN ADDR ; !ptr to smallest name found so far
INTEGER  MAX ADDR ; !ptr to largest  name found so far
INTEGER  PTR ADDR ; !ptr to name currently under examination
INTEGER  SAVE ADDR; !save area for an address
INTEGER  MIN PTR  ; !ptr to entry in array ADDRESS to smallest name
INTEGER  MAX PTR  ; !ptr to entry in array ADDRESS to largest  name
INTEGER  PTR      ; !ptr to entry in array ADDRESS to current  name
!
STRINGNAME  MIN      ; !smallest name found so far
STRINGNAME  MAX      ; !largest  name found so far
STRINGNAME  PTR NAME ; !current  name under examination
STRINGNAME  SAVE NAME; !temporary save area for a name
!
!   Variables for identifying the next variable to output
!
INTEGER      DISP ; !displacement of variable from a nominated base
INTEGER   DV TYPE ; !>0 if array dope vector addresses zero'th element
INTEGER      STACK; !>0 if variable is on the stack
INTEGER  REF NAME ; !>0 if variable is a REF(LOCATION) parameter
INTEGER  GST      ; !>0 if variable is a scalar in the GST area
INTEGER   AN ARRAY; !>0 if variable is an array
!
!   Characteristics of next name to be printed
!
INTEGER      DATA AD   ; !store address of the item
INTEGER      DATA TYPE ; !FORTRAN type of the item, which may
                               !be one of the following:
                               !                       :
                         constinteger  AN INTEGER  = 1,
                                        A REAL     = 2,
                                        A COMPLEX  = 3,
                                        A LOGICAL  = 4,
                                        A CHARACTER= 5
                                        !
INTEGER      DATA BYTES; !the length attribute of the item in bytes
INTEGER      DATA SIZE ; !the length attribute of the item
                                ! as follows:
                                !             3 => 1 byte,  4 => 2 bytes
                                !             5 => 4 bytes, 6 => 8 bytes
                                !                           7 =>16 bytes
INTEGER  NUM DATA ITEMS; !number of values associated with the item

!
!   Work Variables
!
LONGINTEGER  DESC TO PARM
    INTEGER  I
 STRINGNAME  NAME

!
!   SET UP THE LIST OF ADDRESSES
!
 PTR= SYMTABS; CYCLE  NAME CNT=1,1,NO OF NAMES
                      ADDRESS(NAME CNT)= PTR + 4
                      PTR= (PTR + 8 + BYTEINTEGER(PTR+4)) & X'FFFFFFFC'
               REPEAT 
 PTR TO NEXT TABLE= PTR
!
!
!     INITIALISE VARIABLES FOR THE SORT OPERATION
!
!
 MAX PTR= NO OF NAMES
 MIN PTR= 1
!
!   INITIALISE VARIABLES FOR (NEXT) SCAN THROUGH THE LIST
!
NEW SCAN:
!
 MIN ADDR= ADDRESS(MIN PTR); MIN==STRING(MIN ADDR)
 MAX ADDR= ADDRESS(MAX PTR); MAX==STRING(MAX ADDR)
IF  MIN>MAX THENSTART 
             SAVE ADDR= MIN ADDR; MIN ADDR= MAX ADDR
                                  MAX ADDR= SAVE ADDR
             SAVE NAME==MIN     ; MIN     ==MAX
                                  MAX     ==SAVE NAME
            FINISH 

       PTR= MIN PTR + 1
WHILE  PTR<MAX PTR CYCLE 
!
!   SELECT THE NEXT NAME
!
 PTR ADDR= ADDRESS(PTR)
 PTR NAME==STRING (PTR ADDR)
!
!   TEST IF THE NEW NAME SHOULD BE THE MINIMUM
!
IF  MIN>PTR NAME THENSTART 
                  MIN         ==PTR NAME
                  ADDRESS(PTR)= MIN ADDR
                  MIN ADDR    = PTR ADDR
                 FINISHELSESTART 
!
!   TEST IF THE NEW NAME SHOULD BE THE MAXIMUM
!
IF  MAX<PTR NAME THENSTART 
                  MAX         ==PTR NAME
                  ADDRESS(PTR)= MAX ADDR
                  MAX ADDR    = PTR ADDR
                 FINISH 
FINISH 
 PTR= PTR + 1
REPEAT 


!
!   TEST FOR END OF SEARCH
!
    ADDRESS (MIN PTR)= MIN ADDR  AND   ADDRESS(MAX PTR)= MAX ADDR
    MAX PTR= MAX PTR - 1
    MIN PTR= MIN PTR + 1
IF  MIN PTR<MAX PTR THEN  -> NEW SCAN



!   START OUTPUTTING THE VARIABLE NAMES AND VALUES:
                     !
                    {!Initialise} DEFAULT DV TYPE = VERSION; !of compiler
                                    NUM DATA ITEMS= 1
                                        NAME CNT  = 0
UNTIL  NAME CNT=NO OF NAMES CYCLE 
       NAME CNT= NAME CNT+1
!
!   GET THE CHARACTERISTICS OF THE NEXT VARIABLE
!
    SET NAME
IF  STACK¬=0 THEN                   DATA AD= OLD LNB  + DISP          C 
             ELSESTART 
             IF   GST ¬=FALSE THEN  DATA AD= GST ADDR + DISP ELSESTART 
          IF  AN ARRAY¬=FALSE OR                                      C 
                 DATA TYPE= 5 THEN  DATA AD= GLA ADDR + DISP          C 
                              ELSE  DATA AD=     BASE + DISP
             FINISH 
             FINISH 

IF  REF NAME¬= False THENSTART 
    !
    !   Check if a REF(NAME) Parameter is defined
    !
        DESC TO PARM= LONGINTEGER(DATA AD)

    IF  AN ARRAY¬=False AND                                           C 
        DV TYPE ¬=    0 THENSTART 
                 !
                 !   Modify Dope Vector to point to 1st Element
                 !
                     I = INTEGER(DATA AD) >> 27  {extract TYPE and SIZE of desc}
                 IF  I = 1      {TYPE= 0 + SIZE=1} ORC 
                     I = 2      {TYPE= 0 + SIZE=2} ORC 
                     I>=24      {TYPE= 3         } THEN  -> A {invalidity detected}
                       !
!Note, we must first check that we can modify the descriptor
    !  without provoking an interrupt from the MODD instruction
                       !
                      *LD_     DESC TO PARM; !load dope vector
                      *LXN_    DATA AD     ; ! and modify to
                      *MODD_ (XNB +2)      ; !      point to 1st element
                      *STD_    DESC TO PARM; ! and save the result
                 FINISH 

    *LD_   DESC TO PARM
    *VAL_ (LNB +1)
    *JCC_    8,<B>
A:          DATA AD=ADDR(BAD DESC OF PARM)
B: FINISH 

IF  AN ARRAY¬=0 THENSTART 
             IF  ASIZE=0 OR                                           C 
                 DIAG <3 OR                                           C 
                (DIAG =3 AND  STATE>=0) THEN  -> NEXT NAME
             !
             !   HANDLE AN ARRAY
             !
             IF  DATA TYPE=5 THEN  DATA BYTES= INTEGER(DATA AD - 4)
             IF    DV TYPE=0 THEN  DATA AD   = ARRAY ADDRESS1(DATA AD)C 
                             ELSE  DATA AD   = ARRAY ADDRESS2(DATA AD)
                 !
             IF  ASIZE<NUM DATA ITEMS THEN  NUM DATA ITEMS=ASIZE
                   IF  NUM DATA ITEMS = 1   THEN  AN ARRAY=FALSE
             FINISHELSESTART 
             IF  DATA TYPE=5 THEN  DATA BYTES=INTEGER(DATA AD)&X'FFFF'C 
                             AND   DATA AD   =INTEGER(DATA AD+4)      C 
                             ELSESTART 
             IF  REF NAME¬=0 THEN  DATA AD   =INTEGER(DATA AD+4)
                             FINISH ;        FINISH 

IF  STATE=0 THENSTART 
    !
    !   PRINT THE COMMON NAME
    !
    IF  SUBPROG NAME="F#BLCM" THEN  SUBPROG NAME= "BLANK COMMON"      C 
                              ELSE  SUBPROG NAME= "LABELLED COMMON "  C 
                                                   .SUBPROG NAME
                     PRINT STRING ( SUBPROG NAME. "
");                  STATE=1
        FINISH ;         !=>COMMON name printed

          PRINT NAME (NAME)
             !
NEXT NAME:   REPEAT 



ROUTINE  SET NAME
!
!
!   A UTILITY ROUTINE TO PICK UP THE NEXT SCALAR NAME,
!
!                 AND TO DETERMINE ITS CHARACTERISTICS.
!
!
INTEGER  NAME ADDR
INTEGER  I
    NAME ADDR =  ADDRESS(NAME CNT)
    NAME     ==  STRING (NAME ADDR)
    I         =  INTEGER(NAME ADDR - 4)
    DATA TYPE = (I>>24) & 7
IF  DATA TYPE=NONE THENSTART 
    !
    !   Process an Extension to the Identifier Record
    !
        NAME ADDR= SYMTABS + (I & X'FFFFFF')
             I   = INTEGER (NAME ADDR)
        DATA TYPE=(I >> 24) & 7
        DATA SIZE= I >> 28
          DV TYPE= I  & X'80000'
             DISP= INTEGER (NAME ADDR+4)
    FINISHELSESTART 
          !
          !   Extract Info from an ordinary Identifier Record
          !
            DATA SIZE= I >> 28
                 DISP= I & X'FFFFF'
              DV TYPE= DEFAULT DV TYPE
             FINISH 
             !
             STACK= I & X'800000'
         REF NAME = I & X'400000'
          AN ARRAY= I & X'200000'
             GST  = I & X'100000'
                  !
    IF  DATA TYPE¬=5 THEN  DATA BYTES= 1 << (DATA SIZE - 3)
      !
END ; !of SET NAME





INTEGERFN  ARRAY ADDRESS1 (INTEGER  DV ADDR)
!
!
!
!     AN INTEGER FUNCTION WITH ONE PARAMETER WHICH IS THE
!
!        ADDRESS OF A DOPE VECTOR WHICH IS USED TO ACCESS
!
!        ARRAYS RELATIVE TO THE FIRST ACTUAL ELEMENT.
!
!
!     This form of dope vector is the general case for
!     FORTRAN77 when array bound checking is to be
!     performed. It is not used by FORTRAN(G) or FORTRAN(J).
!
!
!     ITS PURPOSE IS TO DETERMINE THE NUMBER OF ELEMENTS IN THE
!           ARRAY AND SET 'NUM DATA ITEMS' ACCORDINGLY, AND TO
!           RETURN (AS THE RESULT) THE START ADDRESS OF THE ARRAY.
!
!

 NUM DATA ITEMS= INTEGER(DV ADDR) & X'FFFFFF'

IF   DATA TYPE=3 THENSTART ; NUM DATA ITEMS=NUM DATA ITEMS>>1
                           ! The dope vector assumes
                           !     that complex values are an ordered
                           !     pair of real values
           FINISHELSESTART 
                 !
IF  (DATA TYPE=1 AND   DATA BYTES=2)  OR                              C 
     DATA TYPE=5 THEN  NUM DATA ITEMS= NUM DATA ITEMS//DATA BYTES
                                     !
                                     !IN INTEGER*2 AND CHARACTER ARRAY
                                     !DOPE VECTORS ALL THE LENGTHS ARE
                                     !IN BYTES, AND NOT ELEMENT SIZE.
                 FINISH 
RESULT = INTEGER(DV ADDR+4)
!
!
!
END ; !of ARRAY ADDRESS1





INTEGERFN  ARRAY ADDRESS2 (INTEGER  DV ADDR)
!
!
!
!     AN INTEGER FUNCTION WITH ONE PARAMETER WHICH IS THE
!
!        ADDRESS OF A DOPE VECTOR WHICH IS USED TO ACCESS
!
!        ARRAYS RELATIVE TO THE ZERO'TH ELEMENT.
!
!
!     This form of dope vector is used by FORTRAN(G) and
!     FORTRAN(J), and also by FORTRAN77 when no array bound
!     checking is required.
!
!
!     ITS PURPOSE IS TO DETERMINE THE NUMBER OF ELEMENTS IN THE
!           ARRAY AND SET 'NUM DATA ITEMS' ACCORDINGLY, AND TO
!           RETURN (AS THE RESULT) THE START ADDRESS OF THE ARRAY.
!
!
INTEGER  K; !---the number of elements from zero'th to beginning

*LXN_  DV ADDR;   *LB_  (XNB +2); !get no of elements from 0'th to start
                  *STB_   K     ; !and store it in K
                  !
*LSS_  (XNB ) ;   !Load bound from zero'th to last
*USH_       8 ;   ! and shift off descriptor type
*ISH_      -8 ;   ! and shift back propagating the sign bit
*ISB_      B  ;   !Then subtract no of elements from 0'th to start
*ST_ NUM DATA                                                         C 
         ITEMS;   ! and store result in NUM DATA ITEMS
             !
IF   DATA TYPE=3 THEN  NUM DATA ITEMS= NUM DATA ITEMS >> 1    ELSESTART 
                 !
IF  (DATA TYPE=1 AND   DATA BYTES=2)  OR                              C 
     DATA TYPE=5 THEN  NUM DATA ITEMS= NUM DATA ITEMS//DATA BYTES     C 
                 AND   K             = K             //DATA BYTES
                                     !In INTEGER*2 and CHARACTER array
                                     !dope vectors all the lengths are
                                     !in bytes, and not element size.
                 FINISH 
                 !
RESULT = INTEGER(DV ADDR+4) + K*DATA BYTES
!
!
!
END ; !of ARRAY ADDRESS2





ROUTINE  PRINT NAME (STRINGNAME  NAME)
!
!
!
!
!     This local routine is used to output the name of a
!
!          variable together with its associated value(s).
!
!
!
ROUTINESPEC  OUTPUT CHARACTER
ROUTINESPEC  OUTPUT LOGICAL
ROUTINESPEC  OUTPUT NUMERIC
!
!Field Widths for Various Item Types:
       !
       CONSTINTEGERARRAY  INTEGER WIDTHS (4:6)=  6, 11, 20
       CONSTINTEGERARRAY  COMPLEX WIDTHS (5:7)= 29, 45, 75
       CONSTINTEGERARRAY     REAL WIDTHS (5:7)= 14, 22, 37
       CONSTINTEGERARRAY   DECS PER SIZE (5:7)=  7, 15, 30


   BYTEINTEGERARRAY  MONITOR BUFFER (0:258);                         !%C
                     MONITOR BUFFER is used either as a workarea for  C 
                                    printing a character value or as  C 
                                    a buffer when outputting floating C 
                                    point values. It is large enough  C 
                                    for the longest F(G) CHARACTER    C 
                                    value (256) plus two delimiting   C 
                                    apostrophes plus a byte for a     C 
                                    string length.
                                    !                                 %C
 For CHARACTER values which are greater than this buffer size, output C 
            is switched to an external area which is acquired via a   C 
            call on F77AUX. This area will be at least 32771 bytes    C 
            long (ie large enough to accomodate the largest possible  C 
            CHARACTER value of FORTRAN77).
            !                                                         %C
            NOTE: Explicit reference to F77AUX must be avoided as     C 
                     FDIAG is also common to FORTRAN(G) and FORTRAN(J)C 
                     and hence the Call Descriptor to F77AUX is pickedC 
                     up from the user program GLA at displacement X'40'

       !----BUFFER POINTERS-----!
       !                        !
INTEGER                         BSTART; !address of the buffer
INTEGER     BPTR DESC       ,   BPTR  ; !pointer to unfilled part of buffer
INTEGER                         BLEN  ; !pointer to end of the buffer
                                        !
INTEGER  LINE LEN   ; !length of unused part of the output buffer
INTEGER       INDENT; !number of spaces reqd at the start of
                      !        a continuation line
INTEGER  I ; !utility variable
INTEGER  J ; !utility variable
INTEGER  REPLY                                                      ;!%C
          from F77AUX in response to a request for a large area
!
!   Format Control Variables
!
INTEGER      FMTCODE ; !type of formatting to be performed on a value
INTEGER      WIDTH   ; !maximum number of digits to output
INTEGER  EXP WIDTH   ; !number of trailing spaces to follow the value
INTEGER      DECIMALS; !number of digits reqd to the right of the '.'
!
SWITCH  PRINT VALUE OF (AN INTEGER:A CHARACTER)

!
!   FIRST PRINT 'NAME='
!
    PRINT STRING ( NAME)
        I=LENGTH ( NAME); IF  I<8 THEN  SPACES (8-I)  AND  I=8
   INDENT= I+3
 LINE LEN=OUTPUT LEN - INDENT
    PRINT STRING (" = ");

{Then check data item address is valid} IF  DATA AD=X'81818181'       C 
                                                                      C 
            OR  DATA AD= 0                                            C 
            OR  DATA AD=-1 THEN  PRINT STRING ("NOT DEFINED")         C 
                           AND   NUM DATA ITEMS= 1                    C 
                           AND      -> RETURN

!Then go and output its value(s):
      !
      !
      BPTR DESC= Byte Desc
         BSTART= ADDR(MONITOR BUFFER(1))
               !
      -> PRINT VALUE OF (DATA TYPE)


!
!   PRINT THE VALUE OF A CHARACTER SCALAR OR ARRAY
!
PRINT VALUE OF (A CHARACTER):
            !
            !
            IF  DATA BYTES>256 THENSTART 
                !
                IF  ADDR OF EXTERNAL AREA=NOT SET THENSTART 
                    !
                    !   Get Access to a Large Area via F77AUX
                    !
                     I= ADDR(DESC OF EXTERNAL AREA)
                     J= ADDR(REPLY)
                                  !
{Do:          }                   *PRCL_      4
{  F77AUX     }                   *LSS_      13     ;   *ST_   TOS 
{     (13,    }                   *LSD_       I     ;   *ST_   TOS 
{         I,  }                   *LXN_     GLA ADDR;   *RALN_  8
{           J)}                   *CALL_ ((XNB +10))
                                   !
                          NUM DATA ITEMS=1 ANDRETURN  IF  REPLY¬=0;  !%C
                                ie forget the variable if area is not available
                    FINISH 
                    !
                BSTART= ADDR OF EXTERNAL AREA+1; !which is at least
            FINISH ;                           !        32771 bytes long
                  !
                  !
                  OUTPUT CHARACTER;   -> RETURN


!
!   PRINT THE VALUE OF A LOGICAL SCALAR OR ARRAY
!
PRINT VALUE OF (A LOGICAL):
            !
           OUTPUT LOGICAL ;  -> RETURN


!
!   PRINT THE VALUE OF AN INTEGER SCALAR OR ARRAY
!
PRINT VALUE OF (AN INTEGER):
             !
             FMTCODE='I'
               WIDTH= INTEGER WIDTHS (DATA SIZE)

           IF  WIDTH< 12 AND  AN ARRAY¬=FALSE THEN  WIDTH= 12
                         !
                         !Ensure that an unassigned array element does
                         !       not upset the columns in which the
                         !       array is output
 -> USE OUTPUT NUMERIC


!
!   PRINT THE VALUE OF A COMPLEX SCALAR OR ARRAY
!
PRINT VALUE OF (A COMPLEX):
            !
            EXP WIDTH= NONE
                WIDTH= COMPLEX WIDTHS (DATA SIZE)  AND  -> PRINT A REAL


!
!   PRINT THE VALUE OF A REAL SCALAR OR ARRAY
!
PRINT VALUE OF (A REAL):
      !
      UNLESS  AN ARRAY=FALSE THEN  EXP WIDTH= 4                       C 
                             ELSE  EXP WIDTH= NONE

                 WIDTH=  REAL WIDTHS (DATA SIZE)
PRINT A REAL: DECIMALS=DECS PER SIZE (DATA SIZE)
              FMTCODE = 'G'
              !
              USE OUTPUT NUMERIC:
                         !
           BPTR= BSTART  AND   BLEN= BPTR + LINE LEN
           !
    OUTPUT NUMERIC


RETURN:       NEWLINE



ROUTINE  OUTPUT CHARACTER
!
!
!
!
!     A local procedure to output the value
!
!        of a Character scalar or array.
!
!
!    (Values are output using PRINT STRING's).
!
!
!
CONSTBYTEINTEGERARRAY  ETOITAB(0 : 255) =                             C 
                        0,   1,   2,   3, 156,   9, 134, 127,
                      151, 141, 142,  11,  12,  13,  14,  15,
                       16,  17,  18,  19, 157,  10,   8, 135,
                       24,  25, 146, 143,  28,  29,  30,  31,
                      128, 129, 130, 131, 132, 133,  23,  27,
                      136, 137, 138, 139, 140,   5,   6,   7,
                      144, 145,  22, 147, 148, 149, 150,   4,
                      152, 153, 154, 155,  20,  21, 158,  26,
                       32, 160, 161, 162, 163, 164, 165, 166,
                      167, 168,  91,  46,  60,  40,  43,  33,
                       38, 169, 170, 171, 172, 173, 174, 175,
                      176, 177,  93,  36,  42,  41,  59,  94,
                       45,  47, 178, 179, 180, 181, 182, 183,
                      184, 185, 124,  44,  37,  95,  62,  63,
                      186, 187, 188, 189, 190, 191, 192, 193,
                      194,  96,  58,  35,  64,  39,  61,  34,
                      195,  97,  98,  99, 100, 101, 102, 103,
                      104, 105, 196, 197, 198, 199, 200, 201,
                      202, 106, 107, 108, 109, 110, 111, 112,
                      113, 114, 203, 204, 205, 206, 207, 208,
                      209, 126, 115, 116, 117, 118, 119, 120,
                      121, 122, 210, 211, 212, 213, 214, 215,
                      216, 217, 218, 219, 220, 221, 222, 223,
                      224, 225, 226, 227, 228, 229, 230, 231,
                      123,  65,  66,  67,  68,  69,  70,  71,
                       72,  73, 232, 233, 234, 235, 236, 237,
                      125,  74,  75,  76,  77,  78,  79,  80,
                       81,  82, 238, 239, 240, 241, 242, 243,
                       92, 159,  83,  84,  85,  86,  87,  88,
                       89,  90, 244, 245, 246, 247, 248, 249,
                       48,  49,  50,  51,  52,  53,  54,  55,
                       56,  57, 250, 251, 252, 253, 254, 255

INTEGER  PTR DESC
INTEGER  PTR     ; !ptr to copy of value to be output
INTEGER  BUFF PTR; !ptr to next portion of the value to be output
INTEGER       LEN; !length of value still to be output
INTEGER       CNT; !length of current record which has been used
INTEGER    LENGTH; !length of the whole value to be output
!
!   Initialise Variables
!
       PTR=     BSTART ; !ptr to beginning of actual value to output
    LENGTH=DATA BYTES+2; !len of character value + allowance
                         !                     for enclosing quotes
IF  LENGTH<12 AND  AN ARRAY¬=FALSE THENSTART 
              !
              !   Insert leading spaces in the buffer
              !
              *LDTB_ X'1900000C'; !By indenting each Character value
              *MODD_   LENGTH   ; !   we ensure that any unassigned
              *LDA_    PTR      ; !   message which is output will
              *MVL_  L =DR ,0,32; !   not upset the columns in which
              *STD_    PTR DESC ; !   the Character array is output
               LENGTH= 12       ; !
              FINISH 

 BYTEINTEGER(           PTR)=QUOTE; !Insert the
                        PTR =PTR+1; !       enclosing quotes
 BYTEINTEGER(DATA BYTES+PTR)=QUOTE; !          in the buffer

!
!   Acquire the (next) Character value
!
AT START OF LINE: CNT= 0
                    !set length of the current record
                    !
NEXT VALUE:
     !
     !   Check for an unassigned variable
     !
     IF  BYTEINTEGER(DATA AD)= 0 THENSTART 
                                  PRINT STRING (NOT ASSIGNED TEXT)
     IF  LENGTH< LINE LEN THEN   SPACES(LENGTH-12)
FINISHELSESTART 

!
!   Copy the next value
!
*LDTB_  BYTE DESC ;   *LDA_  DATA AD; !Perform
*LDB_   DATA BYTES;   *CYD_  0      ; !   MOVE(DATA BYTES
*LDA_   PTR       ;   *MV_  L =DR   ; !       ,    DATA AD , PTR)
        !
        UNLESS  EBCDIC MODE=FALSE THENSTART 
                                  !
                                  *LDB_ DATA BYTES ;  *LSS_ ETOITAB+4
                                  *LUH_ X'18000100';  *LDA_ PTR
                                  *TTR_ L =DR 
                                  FINISH ; !Doing ETOI(PTR,DATA BYTES)
 BUFF PTR= BSTART-1; !prepare to
      LEN= LENGTH  ; !        output the value
!
!   Output the Character value
!
WHILE  LEN>LINE LEN CYCLE 
       !
       BYTEINTEGER(BUFF PTR)= LINE LEN ; !While the value
PRINTSTRING(STRING(BUFF PTR)); NEWLINE ; !      extends over one
            SPACES(INDENT)             ; !      line, continue writing
                                         !      one line's worth
       BUFF PTR= BUFF PTR + LINE LEN   ; !Then select
            LEN=      LEN - LINE LEN   ; !        the next chunk
REPEAT 
      !
     {!Output (the last of) the value } BYTEINTEGER(BUFF PTR)= LEN
                                 PRINTSTRING(STRING(BUFF PTR))
FINISH 
!
!   Test if there are more values
!
IF  NUM DATA ITEMS<=1 THENRETURN 
    NUM DATA ITEMS =  NUM DATA ITEMS - 1
        DATA AD    =      DATA BYTES + DATA AD
        !
        !   Prepare for the next Character value
        !
            CNT= CNT + LENGTH
        IF  CNT<LINE LEN THEN  PRINT SYMBOL (',') AND  CNT=CNT+1
        IF  CNT<LINE LEN                                              C 
                - LENGTH THEN  -> NEXT VALUE
                !
                !   Get a new record
                !
                    NEWLINE
                     SPACES (INDENT)
                -> AT START OF LINE
                         !
END ; !of OUTPUT CHARACTER



ROUTINE  OUTPUT LOGICAL
!
!
!
!
!     A utility procedure to output the value
!
!            of a logical scalar or array.
!
!
!    (Values are written out using PRINT STRING's)
!
!
!
STRING (12) VALUE;   INTEGER  BOOLEAN VALUE
!
INTEGER  PTR; !a note of where we are within the current output line
            !
 BEGIN:  PTR= INDENT

  LOOP: !Perform unassigned checking
        !
        *LDTB_  BYTE DESC;   *CYD_        0          ; !ACC=zero desc
        *LDA_   DATA AD  ;   *LDB_   DATA BYTES      ; ! DR=desc to item
                             *CPS_ L =DR ,0,129      ; !test if assigned
                             *JCC_  7,<EXAMINE VALUE>; ! and -> if it is
                             !
         {Otherwise}   VALUE = NOT ASSIGNED TEXT AND  -> PRINT

EXAMINE VALUE: BOOLEAN VALUE= BYTEINTEGER(DATA AD + DATA BYTES-1) & TRUE
        !
        IF  AN ARRAY¬= FALSE THEN  SPACES(BOOLEAN VALUE + 7)
                             !
   IF  BOOLEAN VALUE = FALSE THEN  VALUE="FALSE"                      C 
                             ELSE  VALUE="TRUE"

        PRINT:  PRINT STRING (VALUE); RETURN  IF  NUM DATA ITEMS<=1
!
!   Select the next Logical array element
!
    NUM DATA ITEMS= NUM DATA ITEMS - 1
        DATA AD   =     DATA BYTES + DATA AD
  PRINT SYMBOL (',');   PTR=   PTR + 13
                    IF  PTR<OUTPUT LEN-13 THEN  -> LOOP
                    !
      {and output the current line}  NEWLINE
                                      SPACES (INDENT)
                                   -> BEGIN
END ; !of OUTPUT LOGICAL





ROUTINE  OUTPUT NUMERIC
!
!
!
!
!     A utility procedure to output the value of
!
!         a Real, Integer, or Complex scalar or array.
!
!
!    (Values of an array are accumulated in a record)
!    (       before they are output.                )
!
!
!
ROUTINESPEC   OUTPUT REAL
ROUTINESPEC   OUTPUT COMPLEX
!
!
CONSTLONGLONGREALARRAY  POWERS OF TEN (5:7)=                          C 
                                                                      C 
                      R'46989680000000003800000000000000' ,
                      R'4D38D7EA4C6800003F00000000000000' ,
                      R'59C9F2C9CD04674E4BDEA40000000000'
                      !
                      !These constants represent 10.0 ** 7            %C
                                                 10.0 **15            C 
                                                 10.0 **30 respectively
                                                 !
     !The values are used to determine whether a REAL*4 or REAL*8
     ! or REAL*16 constant will be output in E format or F format.
!
!
INTEGER     BUFF DESC
INTEGER     BUFF ADDR ; !actual address of formatted value in the buffer
INTEGER  LENGTH
         LENGTH= WIDTH; !copy field width (for complex values)

 CYCLE: !through each element of the current I/O item
        !         and output each in turn
        !
        WIDTH=LENGTH;   {space-fill  }  *LD_   BPTR DESC
                        {  the output}  *LDB_  LENGTH
                        {      field }  *MVL_ L =DR ,0,32
!
!   Test for an unassigned INTEGER or REAL or COMPLEX (real part only)
!
*LDTB_   BYTE DESC;   *LDA_  DATA AD
*LSD_    BYTE DESC;   *LDB_  DATA BYTES
                      *CPS_ L =DR ,0,129
                      *JCC_  8,<UNASSIGNED VARIABLE>

IF  DATA TYPE=A COMPLEX THENSTART 
                        !
                        !   Test for an unassigned imaginary part
                        !
                        *LSD_  BYTE DESC ;  *LDB_  DATA BYTES
                        *LDA_  DATA AD   ;  *INCA_ DATA BYTES
                                            *CPS_ L =DR ,0,129
                        {-> if unassigned}  *JCC_ 8,<UNASSIGNED COMPLEX>
                            !
                           {!--else print the value}     OUTPUT COMPLEX
FINISHELSESTART 
       !
       !   Output an Integer or Real Value
       !
           OUTPUT REAL
       FINISH 

NEXT VALUE:    -> RETURN IF  NUM DATA ITEMS<=1
                         !-> if there are no more values to print
     !
     !   Select the next value
     !
     NUM DATA ITEMS= NUM DATA ITEMS - 1
         DATA AD   =     DATA BYTES + DATA AD
                   !
                   BYTEINTEGER(BPTR)= ','    ; !then insert the
                               BPTR =BPTR + 1; !     trailing comma
!
!   Decide if we need another record
!
IF  BPTR+LENGTH<BLEN THEN  -> CYCLE
                     !
                     MONITOR BUFFER(0)= BPTR - BSTART
                          PRINT STRING (STRING(BSTART-1))
                     NEWLINE;   SPACES (INDENT)
                     !
        BPTR=BSTART  AND   -> CYCLE

UNASSIGNED VARIABLE: !Report an Unassigned
UNASSIGNED COMPLEX : !          Real, Integer, or Complex
         !
         IF  AN ARRAY=FALSE THEN  PRINT STRING (NOT ASSIGNED TEXT)    C 
                            ANDRETURN 
                            !
{For an unassigned   }      *LD_    NOT ASSIGNED TEXT
{    array element,  }      *MODD_  1
{    place the       }      *CYD_   0        ; !ACC= desc(NOT ASSIGNED TEXT)
{      NOT ASSIGNED  }
{    text directly in}      *LDA_   BPTR     ; !DR1= BPTR
{    the buffer and  }      *INCA_  LENGTH   ; !DR1= BPTR + LENGTH
{    right-justify it}      *INCA_ -12       ; !DR1= BPTR + LENGTH - 12
{    within the      }      *MV_   L =DR     ; !then right justify text
{      reserved field}      *STD_   BPTR DESC; !     into the field
       !
       IF  DATA TYPE=A COMPLEX THEN  DATA AD= DATA AD + DATA BYTES
                               !
                               -> NEXT VALUE

!
!   TIDY UP --- PRINT THE (final) LINE
!
RETURN: !If the item is a scalar      }
       {!   then ignore leading spaces} IF  AN ARRAY=FALSE THENSTART 
        !
        *LDTB_  BYTE DESC; *LDB_  BPTR; !DR= descriptor
        *MODD_  BSTART   ;              !        to the buffer
        *LDA_   BSTART   ;              !               contents
                         !
        *SWEQ_ L =DR ,0,32            ; !skip over leading spaces
        *STD_   BUFF DESC             ; ! and save address of 1st character
                                        !
                                        FINISHELSE  BUFF ADDR= BSTART

          BYTEINTEGER(BUFF ADDR-1)= BPTR - BUFF ADDR
 PRINT STRING (STRING(BUFF ADDR-1))
      RETURN 



ROUTINE  OUTPUT COMPLEX
!
!
!
!     A LOCAL PROCEDURE WHICH OUTPUTS A COMPLEX VALUE
!
!
!
!
INTEGERFNSPEC  WIDTH FOR (INTEGER  DATA AD)
               !
INTEGER        WIDTH1; !field width reserved for the real part
INTEGER        WIDTH2; !field width reserved for the imaginary part
INTEGER        WIDTH3; !least width required for the complex value
          !
          !Note that, if possible, the field width used is twice the
          !     field required for a real value plus space for the
          !     opening and closing bracket and the separating comma
                !
INTEGER  SPACES REQD
                 !to right-justify the value within the determined field
!
!   Determine the field widths for each complex part
!
    WIDTH1= WIDTH FOR (DATA AD)
    WIDTH2= WIDTH FOR (DATA AD + DATA BYTES)
    WIDTH3= WIDTH1 + WIDTH2 + 3; !=Width(imaginary part)  + '('
                                 !+Width(real part) + ',' + ')'

!
!   Note any leading spaces required to right-justify the value
!
    SPACES REQD= LENGTH-WIDTH3
IF  SPACES REQD> 0 THEN  BPTR= BPTR + SPACES REQD

!
!   Now Output the Real Part
!
 BYTEINTEGER(BPTR)= '('   AND   BPTR=BPTR+1
            WIDTH = WIDTH1
                    OUTPUT REAL
 BYTEINTEGER(BPTR)= ','   AND   BPTR=BPTR+1

!
!   Then Output the Imaginary Part
!
   DATA AD=DATA AD + DATA BYTES
     WIDTH=WIDTH2
           OUTPUT REAL

!
!   Finally Return
!
 BYTEINTEGER(BPTR)= ')'
             BPTR = BPTR+1
          RETURN 

INTEGERFN  WIDTH FOR (INTEGER  DATA AD)
!
!
!
!
!     A LOCAL PROCEDURE WHICH RETURNS THE FIELD WIDTH TO BE USED
!
!          TO OUTPUT A PART OF A COMPLEX VALUE. THE FACTORS
!
!          INVOLVED ARE THE SCALE OF THE VALUE AND THE NUMBER
!
!          OF SIGNIFICANT DIGITS REQUIRED.
!
!
!It should be noted that the value returned will be exactly
!   sufficient to format the number without any leading spaces.
!
!
!
LONGLONGREAL   A    ; !a copy of the value to be output
     INTEGER   SIGN ; !set to one if the value is -ve, else set to zero
     INTEGER   WIDTH; !----the result returned

!
!   Get a copy of the complex part
!
IF  DATA SIZE=5 THEN  A=        REAL(DATA AD)  ELSESTART 
IF  DATA SIZE=7 THEN  A=LONGLONGREAL(DATA AD)  C 
                ELSE  A=    LONGREAL(DATA AD); FINISH 
                !
IF  A<0.0 THEN  A=-A AND   SIGN=TRUE                                  C 
                     ELSE  SIGN=FALSE
!
!   Determine whether 'F' or 'E' formatting will be used
!
IF  A>=POINT ONE AND  A<POWERS OF TEN(DATA SIZE) THENSTART 
           !
          {!'F' formating will be used} WIDTH=DECIMALS+1
                                        WIDTH=   WIDTH+1 IF  A<1.0
                           FINISHELSE   WIDTH=DECIMALS+5
RESULT =WIDTH+SIGN
             !(add on one if value is negative)
END ; !of WIDTH FOR
END ; !of OUTPUT COMPLEX



ROUTINE  OUTPUT REAL
!
!
!
!
!     A utility procedure to format a real or integer value (as
!       described by the variables DATA TYPE, DATA AD, and DATA
!       BYTES) at address BPTR according to the values in WIDTH,
!       FMTCODE, and DECIMALS.
!
!    (In addition, the variable EXP WIDTH indicates the number)
!    (of spaces required on the right of a real value.        )
!
!
!
LONGLONGREALFNSPEC    INTO RANGE   (LONGLONGREAL  VALUE)
       !
  BYTEINTEGERARRAY  OUTPUT AREA (0:47)
                     !Work-area for assembling
                     !          the digits to be output
!
!   POINTERS
!
INTEGER  AREA DESC     ; !Descriptor used to
INTEGER  AREA PTR      ; !           save numerals in the work-area
                         !
INTEGER  PTR DESC      ; !Descriptor used to construct a
INTEGER  PTR           ; !           formatted value in the output area

INTEGER  PTR MAX       ; !addresses the end of the output field (+1)


!
!   LOCAL VARIABLES DESCRIBING THE FORMAT CODE
!
INTEGER  FORMAT        ; !initially set from FMTCODE
INTEGER    DECS        ; !initially set from DECIMALS
INTEGER    LENGTH      ; !initially set from WIDTH


!
!   VARIABLES DESCRIBING THE VALUE TO FORMAT
!
LONGLONGREAL       A   ; !the value in question precision is required
 LONGINTEGER  LONG I   ; ! used to FIX the value of A
                         !
     INTEGER  SIGN     ; !the sign to be output with the value
                                  !     = '+' or '-'
                                  !else =  0  if no sign is required
     INTEGER  EXP      ; !magnitude of value expressed as multiple of 10
     INTEGER   N , I   ; !Work variables


!
!   FORMATTING CONTROL VARIABLES
!
INTEGER  MAX INT DIGITS; !maximum number of digits that may be
                         !        output left of the decimal point
INTEGER      INT DIGITS; !number of digits required left of the '.'
INTEGER  LEADING ZEROS ; !number of zeros required right of the '.'
INTEGER    TOTAL CHARS ; !number of digits required both left
                         !       and right of the decimal point


!
!   VARIABLES ASSOCIATED WITH FORMATTING AN EXPONENT
!
INTEGER  EXPONENT      ; !Value of exponent to format
INTEGER  EXP TYPE      ; !Qualifier to be associated with the exponent
                         !      = 'Q' for REAL*16
                         !      = 'D' for REAL* 8
                         !      = 'E' otherwise or FORMAT='E'
!
!   INITIALISE VARIABLES
!
    LENGTH  =      WIDTH
    PTR     =       BPTR
    PTR MAX =        PTR + LENGTH
    PTR DESC=STRING DESC ! LENGTH


         FORMAT =FMTCODE


!
!
!   PICK UP THE VALUE TO BE FORMATTED NUMERICALLY
!
!
IF  FORMAT='G' THENSTART ;      !LOAD UP A REAL VALUE
          !
          IF  DATA BYTES= 8 THEN  A=    LONGREAL(DATA AD)    ELSESTART 
          IF  DATA BYTES=16 THEN  A=LONGLONGREAL(DATA AD)    C 
                            ELSE  A=        REAL(DATA AD);   FINISH 
                                  A=A + 0.0
                                  !normalise
FINISHELSESTART 
       !
       !   LOAD UP AN INTEGER VALUE
       !
       IF  DATA BYTES=8 THENSTART 
                        !
                        !   Handle an INTEGER*8
                        !
                         A= LONGINTEGER(DATA AD)
       FINISHELSESTART 
       !
       !   Handle an INTEGER*4 or INTEGER*2
       !
       IF  DATA BYTES=2 THENSTART 
                        *LDTB_ X'58000002'; *LDA_ DATA AD
                        *LSS_   (DR )
                        *USH_     16
                        *ISH_    -16      ; *ST_  I
                     FINISHELSE   I=INTEGER (DATA AD)
                         -> QUICK I FORMAT
                           FINISH 
       FINISH 


!
!   HANDLE A NEGATIVE VALUE
!
IF  A<0.0 THEN  A=-A  AND     SIGN=MINUS  AND  LENGTH=LENGTH-1        C 
                      ELSE    SIGN= NONE

{make a descriptor to}  *LD_   OUTPUT AREA;       *STD_   AREA DESC
{       the work-area}           AREA DESC= X'01000000' ! AREA DESC
                     !                       (switch off bound checking)
               EXP=1;!  %FINISH
                              !preparing for numeric formatting


IF  FORMAT='I' THEN  -> I FORMAT
          !
!***********************************************************************
!
!     HANDLE 'G' FORMAT
!
!***********************************************************************
!
G FORMAT:                                  DECS=  DECIMALS
  !
IF  POINT ONE<=A<POWERS OF TEN(DATA SIZE) THENSTART 

!
!   OUTPUT THE VALUE WITHOUT AN EXPONENT (and left-justify it as well)
!
    A =INTO RANGE (A) + 5.0/POWERS OF TEN(DATA SIZE)
IF  A>=10.0 THENSTART 
               A=  A/10.0; !apply correction if rounding put
             EXP=EXP+1   ; !  the value back out of range
            FINISH 

!
!   Determine actual WIDTH and DECIMALS to use
!
    LENGTH= LENGTH - EXP WIDTH; !reduce LENGTH by spaces reqd on the right
      DECS=   DECS - EXP      ; !reduce DECS by digits reqd left of '.'
      !
      -> COLLECT DIGITS
                      !
                      !
FINISH 
!
!   OUTPUT THE NUMBER WITH AN EXPONENT
!                                                                    !%C
 -> E FORMAT                            ; !GO AND LET 'E' FORMATING
                                          !    DO ALL THE WORK
!***********************************************************************
!
!     HANDLE 'E' FORMAT
!
!***********************************************************************
!
E FORMAT:
  !
 {!Initialise variables}            DECS=DECS-1
                 !
                 IF  A=0.0 THEN  EXPONENT=NONE AND  EXP=NONE ELSESTART 

!Bring the value into the range:  10.0> A >=1.0
       !
       A= INTO RANGE (A)  + 5.0/POWERS OF TEN (DATA SIZE)
   IF  A> 10.0 THENSTART  ;                              !apply rounding
                  A=A/10.0; !apply correction
                EXP=EXP+1 ; !   if rounding took value back out of range
               FINISH 

 EXPONENT= EXP-1           ; !determine the value of the exponent part
           EXP=1           ; FINISH 


!
!   PRODUCE THE DECIMAL PART
!
    LENGTH= LENGTH - 4;  FORMAT= 'E'
          !
         -> COLLECT DIGITS
                   !expect a return with DR pointing to
                   !       the remainder of the output field


!OUTPUT THE EXPONENT:
 OUTPUT THE EXPONENT:   !ANALYSE THE EXPONENT TO FORMAT:
!OUTPUT THE EXPONENT:
                !
                IF  EXPONENT<0 THEN  SIGN=MINUS                       C 
                               ELSE  SIGN=PLUS


!
!   Determine the characteristic of the exponent
!
IF  VERSION¬=F77 AND  DATA BYTES>4 THENSTART 
                 IF   DATA BYTES>8 THEN  EXP TYPE= 'Q'                C 
                                   ELSE  EXP TYPE= 'D'
                             FINISHELSE  EXP TYPE= 'E'

    {and write it into the field}                  *LDB_    4
                                    *LB_ EXP TYPE; *MVL_ L =1

!
!   Produce the exponent part
!
*LB_   SIGN    ;   *MVL_  L =1     ; !get the sign and move it into buffer
                   *STD_   PTR DESC; !    and save address of exp digits
                   !
*LSS_  EXPONENT;   *CDEC_     0    ; !get the exponent (in decimal form)
*MPSR_ X'24'   ;   *DSH_      13   ; !    and left-justify it in the ACC
                   *SUPK_ L =DR    ; !----and format into EBCDIC digits
 -> FINALISE INTEGER
               !Jump to convert EBCDIC digits into ISO digits



!***********************************************************************
!
!     Perform formatting of Real values
!
!***********************************************************************
!

COLLECT DIGITS:
!
!
!     DETERMINE THE VARIABLES WHICH CONTROL FORMATTING
!
!
    MAX INT DIGITS= LENGTH  -  DECS - 1       ; != number of digits that
                                                !     may be output left
                                                !     of the decimal pt.
        INT DIGITS= EXP
                  !
                  !INT DIGITS is the number of digits that are
                  !           required to the left of the decimal point

IF  INT DIGITS<=0 THENSTART 
    !
    !   Determine how many leading zeros are required if value is < 1.0
    !
    IF  MAX INT DIGITS=NONE THENSTART 
                            !
                    LEADING ZEROS= -INT DIGITS AND   INT DIGITS= NONE
        FINISHELSE  LEADING ZEROS=1-INT DIGITS AND   INT DIGITS= 1
                      TOTAL CHARS=  INT DIGITS - LEADING ZEROS + DECS
                                                                     !%C
GENERATE LEADING ZEROS: !in the work area and in EBCDIC
         !
         *LD_      AREA DESC  ;   *LDB_   LEADING ZEROS
         *LB_    EBCDIC ZERO  ;   *MVL_        L =DR 
         *LD_      AREA DESC  ;   *MODD_  LEADING ZEROS
         *STD_     AREA DESC  ;
                !save the address of the next free byte of the work area

FINISHELSESTART ;
           !
           !   Determine total number of numerals required if value>=1.0
           !
               TOTAL CHARS= INT DIGITS + DECS
              FINISH 


FORMAT DIGITS:
!
!
!   ACQUIRE ALL THE DIGITS (AND POSSIBLY MORE) THAT ARE NEEDED
!
!               The code below produces 12 digits at a
               !    time and saves them (in EBCDIC) in
               !    the workarea.
                                !
                                !   DO FORMATTING AT EXTENDED PRECISION
    A= A * TEN TO THE 11     ;  !
                                       *LD_    AREA DESC
WHILE  TOTAL CHARS>0 CYCLE 
       TOTAL CHARS=TOTAL CHARS-12
                     !
                     *LSD_   A     ;   *FIX_  B 
                     *MYB_   4     ;   *USH_  B 
                                   !Perform    LONG I= INT PT (A)
                                   !
                                   !  (NOTE that INT PT is an INTEGER
                                   !        function and not LONGINTEGER
                                   !     ---hence the Assembler)
                     *ST_    LONG I;
                     *CDEC_     0  ;
                     *DSH_     19  ;   *MPSR_ X'24'
                     *SUPK_ L =12  ;
                                   !
                                   !We have now:
                                   !    1/. got the value in decimal
                                   !    2/. moved it to the top of ACC
                                   !    3/. set condition code to 1
                                   !    4/. acquired 12 alphanumerics
                      A= (A - LONG I) * TEN TO THE 12
REPEAT ;


!
!
!   FORM THE FORMATTED VALUE IN THE OUTPUT FIELD
!
!
    PTR= PTR + (MAX INT DIGITS - INT DIGITS)
                    !
                    !point to where the first significant char should go

IF  SIGN¬=NONE THENSTART ; *LB_    SIGN;   *LDB_   1;   *LDA_   PTR
                           *MVL_   L =1;                *STD_   PTR DESC
                           !
                           !Move any required sign into the field
                                                          FINISH 
!
!   Write out the digits to the left of the decimal point
!
   *LSD_ OUTPUT AREA  ; !ACC -> digits generated in the work-area
   *LDB_    INT DIGITS; !DR  -> sub-field allocated to the left
   *LDA_    PTR       ; !                 hand side of the decimal point
                                                                       !
   *MV_    L =DR        ;   *ST_    AREA DESC
           !perform move;          !save ptr to remainder of the digits
!
!   Write out the decimal point
!
IF  FORMAT='I' THEN  -> FINALISE FORMATING
               !
               *LB_    DOT;   *LDB_   1;   *MVL_  L =1
!
!   Write out the digits to the right of the decimal point
!
IF  DECS>0 THENSTART 
           !
           *LSD_   AREA DESC;   *LDB_   DECS
                                *MV_   L =DR 
                                FINISH 

FINALISE FORMATING: !by translating the EBCDIC numerals into ISO
                    !
                    *STD_  N;   *LDA_   NIL; !construct a descriptor
                    *LDB_  I;   *MODD_  PTR; !       to the numerals
                                !
                                *MVL_  L =DR ,31,32; !and perform the %C
                                                          translation


IF  FORMAT='E' THEN  -> OUTPUT THE EXPONENT
               !
               !Jump if format code is 'E' and continue
               !     to format the exponent characteristic
 -> EXIT
       !
       !
!***********************************************************************
!
!     HANDLE 'I' FORMAT for INTEGER*8
!
!***********************************************************************
!
I FORMAT:
    !
IF  A=0.0 THEN  -> OUTPUT A ZERO INTEGER

    A=INTO RANGE( A + 0.5 )
     !apply rounding and bring the value into the range  10.0> A >=1.0

!
!   Initialise formatting control variables
!
           INT DIGITS= EXP       ; !number of significant digits
         TOTAL  CHARS= INT DIGITS; !                 that must be output
       MAX INT DIGITS=     LENGTH; !number of digits that may  be output

            -> FORMAT DIGITS


     OUTPUT A ZERO INTEGER:
!    OUTPUT A ZERO INTEGER:
!    OUTPUT A ZERO INTEGER:
            !
            BYTEINTEGER(PTR MAX-1)= NOUGHT  AND   -> EXIT

!***********************************************************************
!
!     HANDLE 'I' FORMAT   -----QUICKLY
!
!***********************************************************************
!
QUICK I FORMAT:   !Simplified code may be used if the corresponding
                  !           I/O item is an INTEGER*2 or INTEGER*4.
                  !
IF  I=0 THEN  -> OUTPUT A ZERO INTEGER

IF  I<0 THEN  SIGN=MINUS                                              C 
        ELSE  SIGN= NONE

                              N=15 - LENGTH
{If LENGTH is greater   } IF  N< 0 THENSTART 
{   than 15 then the    }
{   code below cannot   }           PTR= PTR - N
{   generate any leading}             N= 0
{   spaces automatically}
{So PTR must be re-set  }          FINISH 
!
!   FORMAT THE INTEGER
!
   *LSS_   I;   *CDEC_  0; !First load the value and convert into decimal
   *DSH_   N
           !This moves the number up the ACC so that the subsequent SUPK
           !instruction produces the right number of leading spaces as
           !            well as the required digits.
   *LDTB_  STRING DESC;  *LDA_   0
   *LDB_      PTR MAX ;  *MODD_  PTR     ; !Get and save a descriptor
                         *STD_   PTR DESC; !        to the output field
                         *MPSR_    X'20' ; !Set condition code to zero
   *SUPK_  L =DR ,0,64;
               !formats the decimal value in ACC into EBCDIC characters.
               !        Any leading zeros produce EBCDIC spaces.
!
!   Insert any sign
!
   *LD_   TOS  ;              !unstack descriptor generated by SUPK
   *LB_    SIGN;   *JAT_   12,<FINALISE INTEGER>; !skip if no sign reqd
                   *MVL_   L =DR                ; !else move the sign in
!
!   Translate the result into ISO
!
FINALISE INTEGER:   *LD_   PTR DESC   ; !convert EBCDIC zones X'F0'
                    *MVL_ L =DR ,31,32; !      into ISO zones X'30'

!***********************************************************************
!
!     END OF HANDLING OUTPUT FORMATS
!
!***********************************************************************
!

EXIT:     BPTR= PTR MAX
             !
       RETURN 
!
!
!
!***********************************************************************
!
!     ROUTINES FOR HANDLING OUTPUT FORMATS
!
!***********************************************************************
!

LONGLONGREALFN  INTO RANGE (LONGLONGREAL  X)
!
!
!
!     A PROCEDURE WHICH BRINGS THE VALUE OF THE GIVEN
!
!       PARAMETER INTO THE RANGE   10.0> X >=1.0
!
!
!Additionally, the variable EXP is changed to reflect the
!              magnitude (scale of 10) of the parameter.
!
!
LONGLONGREAL  Y
LONGLONGREAL  Z
!
INTEGER  I; !a work variable

IF  X>=10.0 THENSTART 
    !
    !   The value is too large
    !
    IF  X<TEN TO THE 75 THENSTART 
        !
        !   Find the scale of the number and bring it into range
        !
         I= 1;  Z= 10.0
                Y=100.0
                !
                Z=Y AND  Y=Z*10.0 AND  I=I+1 WHILE  X>=Y
                !
                X=X/Z AND  EXP=EXP+ I
        FINISHELSE         EXP=EXP+75  AND  X=X/TEN TO THE 75
        FINISH 

IF  X<1.0 THENSTART 
    !
    !   The value is too small
    !
           X=X*10.0 AND  EXP=EXP-1 WHILE  X<TEN TO THE MINUS 75
            !
           I=  1
           Z=POINT ONE
            !
           I=I+1 AND  Z=Z/10.0 WHILE  X<Z
            !
         EXP=EXP-I
           X= X * (10.0**I)
    FINISH 

!
!   Return
!
RESULT = X
      !
END ; !of INTO RANGE

END ; !of OUTPUT REAL

END ; !of OUTPUT NUMERIC

END ; !of PRINT NAME

END ; !of SORT AND PRINT NAMES





ROUTINE  DUMP(INTEGER  START, FINISH)
INTEGER  I, J
      I=START&(-4)
      WHILE  I<FINISH CYCLE 
         PRINTSYMBOL('(')
         PHEX(I)
         PRINTSTRING(")  ")
         CYCLE  J=I,4,I+28
            IF  J>=FINISH THEN  ->L
            SPACES(2)
            PHEX(INTEGER(J))
         REPEAT 
L:       NEWLINE
         I=I+32
      REPEAT 
END ; !of DUMP



ROUTINE  PHEX (INTEGER  VALUE)
!
!
!
!
!     A utility routine which prints the parameter as a
!
!               hexadecimal value on the currently
!
!               selected output stream.
!
!
!
CONSTBYTEINTEGERARRAY  HEX(0:15)= '0' , '1' , '2' , '3' ,
                                  '4' , '5' , '6' , '7' ,
                                  '8' , '9' , 'A' , 'B' ,
                                  'C' , 'D' , 'E' , 'F'
INTEGER  I
CYCLE  I=28,-4,0
 PRINT SYMBOL (HEX(VALUE>>I&15))
REPEAT 

END ; !of PHEX










END ; !of FDIAG
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
ENDOFFILE