Trailing-Edge
-
PDP-10 Archives
-
BB-4157F-BM_1983
-
fortran/ots-debugger/fornml.mac
There are 9 other files named fornml.mac in the archive. Click here to see a list.
SEARCH FORPRM
TV FORNML NAMELIST AND LIST-DIRECTED I/O 7(3250)
SUBTTL NAME LIST SEQUENTIAL ACCESS CALLING SEQUENCES - 28-Oct-81
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1972, 1983
COMMENT \
***** Begin Revision History *****
3056 JLC 23-Mar-82
Created from FORCNV.MAC. Changed some global refs.
3057 JLC 25-Mar-82
List-directed and namelist output must clear both encoded
words to get free format.
3063 BL 26-Mar-82
Insert NAMELIST character I/O code.
3074 BL 31-Mar-82
Cleanup NAMELIST character I/O stuff[3063].
3106 BL 12-Apr-82
Enable us to handle substrings of character scalars.
3112 BL 15-Apr-82
Change SKIPN to SKIPE.
3120 BL 19-May-82
Ensure no delimiters after LD character output.
3131 JLC 11-Jun-82
Make more delimiters, namely "=" and "(", legal for
NAMELIST I/O, since they can be obtained by abortive
call to %LINT (e.g. A(1)=3,TRUE=3).
3133 BL 16-Jun-82
Code review changes for LD/NM character stuff.
3136 JLC 26-Jun-82
Fix G-float bug - namelist and list-directed I/O were
requesting input of a value of type DP%DPR, so got
overflow when outside the normal range but legal for
GFLOAT.
3150 JLC 13-Jul-82
Fix output of integer 0, was calling %INTO, should have been
calling %GINTO.
3154 JLC 20-Jul-82
Fix G-floating list-directed input.
3164 BL 27-Aug-82
NAMELIST bug...DECRP was not resetting input string count
(NLSWRD). Sometimes resulted in incorrect input string byte
pointers (NLSPTR/NLCPTR).
3250 JLC 7-Jan-83
Support list-directed output of Hollerith literals.
***** End Revision History *****
\
COMMENT $
READ (u,name)
READ (u,name,END=c,ERR=d)
MOVEI 16,ARGBLK 0 89 12 14 1718 35
PUSHJ 17,NLI. ------------------------------------
! 3 !TYP!I! X ! u -unit# !
------------------------------------
! 4 !TYP!I! ! END=c !
------------------------------------
! 5 !TYP!I! ! ERR=d !
------------------------------------
! 6 !TYP!I! X ! IOSTAT=i !
------------------------------------
! 10 !TYP!I! X ! NAMELIST addr !
------------------------------------
WRITE (u,name)
WRITE (u,name,END=c,ERR=d)
MOVEI 16,ARGBLK 0 89 12 14 1718 35
PUSHJ 17,NLO. ------------------------------------
! 3 !TYP!I! X ! u -unit# !
------------------------------------
! 4 !TYP!I! ! END=c !
------------------------------------
! 5 !TYP!I! ! ERR=d !
------------------------------------
! 6 !TYP!I! X ! IOSTAT=i !
------------------------------------
! 10 !TYP!I! X ! name list addr !
------------------------------------
The NAMELIST table illustrated below is generated form
the FORTRAN NAMELIST STATEMENT. The first word of the
table is the NAMELIST name in sixbit format. Following
that are a number of two-word entries for scalar
variables, and a number of (N+3)-word entries for array
variables, where N is the dimensionality of the array.
The NAMELIST argument block has the following format.
NAMELIST ADDR/ 0 89 12 14 1718 35
------------------------------------
! SIXBIT /NAMELIST NAME/ !
------------------------------------
! NAME LIST ENTRIES !
------------------------------------
! 0 !
------------------------------------
SCALAR ENTRIES
012 89 12 14 1718 35
------------------------------------
! SIXBIT /SCALAR NAME/ !
------------------------------------
!10! 0 ! T !I! X ! SCALAR ADDR !
------------------------------------
ARRAY ENTRIES differ in that blocks generated by V6 and earlier
compilers have ARRAY SIZE and OFFSET as halfwords in the
third word of the block. This is signaled by the first bit
of word 2 being zero. V7 and later versions will set the first
bit in word 2 and place ARRAY SIZE in word 3 and ARRAY OFFSET
in word 4 of the block.
V6 and earlier: 012 89 12 14 1718 35
------------------------------------
! SIXBIT /ARRAY NAME/ !
------------------------------------
!00!#DIM! T !I! X ! BASE ADDR !
------------------------------------
! SIZE ! OFFSET !
------------------------------------
! ! !I! X ! FACTOR 1 !
------------------------------------
! ! !I! X ! FACTOR 2 !
------------------------------------
! ! !I! X ! FACTOR 3 !
------------------------------------
! ! !I! X ! FACTOR N !
------------------------------------
V7: 012 89 12 14 1718 35
------------------------------------
! SIXBIT /ARRAY NAME/ !
------------------------------------
!10!#DIM! T !I! X ! BASE ADDR !
------------------------------------
! NUMBER OF ENTRIES !
------------------------------------
! OFFSET !
------------------------------------
! ! !I! X ! FACTOR 1 !
------------------------------------
! ! !I! X ! FACTOR 2 !
------------------------------------
! ! !I! X ! FACTOR 3 !
------------------------------------
! ! !I! X ! FACTOR N !
------------------------------------
$
SUBTTL JON CAMPBELL /JLC/EDS/AHM
ENTRY %NLI,%NLO,%LDI,%LDO,%LDIST,%LDOST
EXTERN %IBYTE,%IBYTC,%OBYTE,%IRECS,%ORECS,%SAVE4,%IBACK
EXTERN %RIPOS,%SIPOS,%ROPOS,%SOPOS,%GTBLK,%PUSHT,%POPT
EXTERN IO.ADR,IO.INC,IO.NUM,IO.TYP,IO.INF,ENC.WD,A.NML,SCL.SV,IO.SIZ
EXTERN %FLRFR,%FLRBX,%FLFSG,ENC.W2,T.NML,%FTSLB
EXTERN %FLSPR,%FLDPR,%FLGPR
EXTERN %GRIN,%GROUT,%INTI,%GINTO,%LINT,%LOUT,%OCTI,%OCTO,%SIZTB
EXTERN %IOERR,%POPJ,%POPJ1,%ABORT,%SETAV,%UDBAD,%GTBLK,%MVBLK,%OMBYT
SEGMENT DATA
%ALASZ==10 ;SIZE OF ARRAYS FOR STRING INFO
%ALISZ==100 ;INITIAL SIZE FOR STRING CORE ALLOCATION
NLSGN1: BLOCK 1 ;LOCAL REAL PART SIGN
NLSGN2: BLOCK 1 ;LOCAL IMAGINARY PART SIGN
NLSGN.: BLOCK 1 ;SIGN OF ENTIRE VALUE
NLFLG.: BLOCK 1 ;-1=END OF DATA, 0=NULL, 1=NON-NULL
CHRLST: BLOCK 1 ;Last LD output was character (no delimiters)
DLFLG.: BLOCK 1 ;FLAG TO SCAN FOR END DATA DELIM
NLRFR: BLOCK 2 ;RAW FRACTION FROM FLIRT
NLRBX: BLOCK 1 ;RAW BINARY EXPONENT TO MATCH
NLRFR2: BLOCK 2 ;RAW FRACTION OF IMAGINARY PART
NLRBX2: BLOCK 1 ;RAW BINARY EXPONENT OF IMAGINARY PART
NLINFO: BLOCK 1 ;INFO ABOUT FLIRT NUMBER (REAL PART)
NLVAL.: BLOCK 2 ;VALUE FOUND
NLVL2.: BLOCK 2 ;2ND VALUE FOR COMPLEX
NLRP.: BLOCK 1 ;REPEAT COUNT
NLDIM.: BLOCK 1 ;# OF DIMENSIONS
NLVAR.: BLOCK 1 ;PNTR TO VARIABLE IN ARG LIST
NLNAM.: BLOCK 1 ;NAME OF NAMELIST/VARIABLE
NLARG.: BLOCK 1 ;ADDRESS OF ARG LIST
NLCVL.: BLOCK 2 ;CONVERTED VALUE
NLADD.: BLOCK 1 ;ADDRESS OF USER'S VARIABLE
NLINC.: BLOCK 1 ;OFFSET BETWEEN USER'S ARRAY ENTRIES
NLSIZ.: BLOCK 1 ;SIZE OF USER'S ARRAY ENTRIES
NLOFF.: BLOCK 1 ;Offset for calculation of element address
NLFCT.: BLOCK 1 ;Address of array's first factor
NLEMS.: BLOCK 1 ;Elements in array
CNVTYP: BLOCK 1 ;CONVERTED VALUE TYPE
VALTYP: BLOCK 1 ;ORIGINAL VALUE TYPE
VARTYP: BLOCK 1 ;VARIABLE TYPE
TOTYPE: BLOCK 1 ;TYPE TO CONVERT TO
OSIZE: BLOCK 1 ;SIZE OF SUBSEQUENT OUTPUT DATA ELEMENT
NLBFLN: BLOCK 1 ;Byte size of LD/NL input string buffer
NLSBYT: BLOCK 1 ;Byte count of LD/NL input string
NLSWRD: BLOCK 1 ;Word count of LD/NL input string
NLCWRD: BLOCK 1 ;Current word count of LD/NL input string
NLSPTR: BLOCK 1 ;Pointer to beginning of LD/NL string buffer
NLCPTR: BLOCK 1 ;Current pointer to LD/NL input string
FINFLG: BLOCK 1 ;FLAGS FOR END OF DATA
LDLFLG: BLOCK 1 ;FLAGS FOR LEGAL DELIMITERS
NLNUM.: BLOCK 1 ;# OF USER'S ARRAY ENTRIES TO FILL
NLVFC.: BLOCK 1 ;FLAGS ALLOWED FOR 1ST CHAR OF VARIABLE
NLFV.: BLOCK 1 ;VARIABLE ENTRY HAS BEEN FILLED
TMPFLG: BLOCK 1 ;[JLC] TEMP STORAGE FOR NAMELIST FLAG (P1)
;CHARACTER FLAGS - SET BY ROUTINE GETCHR
;IN ORDER TO TEST FOR MULTIPLE CHARACTERS (OF A CERTAIN TYPE, FOR INSTANCE),
;EACH CHARACTER HAS BEEN GIVEN AN ASSOCIATED FLAG (PICKED UP IN TABLE
;NLCFLG). ALL SPECIAL CHARACTERS (E.G. "*","$") HAVE THEIR OWN FLAGS, AND
;ALL ALPHABETIC CHARACTERS ARE GIVEN THE FLAG "ALFLAG". THIS TECHNIQUE
;COMPRESSES THE TESTING REQUIRED FOR DELIMITERS, ETC., AND MAKES IT MORE
;GENERAL.
COLFLG==0
SEMFLG==0
LSBFLG==0
RSBFLG==0
RABFLG==0
LABFLG==0
ATFLAG==0
NSFLAG==0
EOLFLG==2
DIGFLG==10
COMFLG==20
SPCFLG==40
ALFLAG==100
LPRFLG==200
RPRFLG==400
PNTFLG==1000
SQFLAG==2000
DQFLAG==4000
SGNFLG==10000
MINFLG==10000
PLSFLG==10000
NLSFLG==20000
NLEFLG==40000
AMPFLG==40000
DOLFLG==40000
NULFLG==100000
SLHFLG==200000
LOGFLG==400000
ASTFLG==1,,0
EQUFLG==2,,0
SEGMENT CODE
;LIST-DIRECTED INPUT & OUTPUT ROUTINES
;USES COMMON SUBROUTINES IN THE NAMELIST CODE TO PICK UP
;VALUES.
%LDIST: MOVX T1,SLHFLG ;SLASH OR ERROR ENDS DATA
MOVEM T1,FINFLG
MOVX T1,COMFLG+SPCFLG+SLHFLG+NULFLG+ASTFLG+EOLFLG
;LEGAL DELIMITERS [3063]
MOVEM T1,LDLFLG ;FOR CHECKING AFTER A SCAN
SETZM NLVFC. ;NO VARIABLES ALLOWED
PUSHJ P,NLINIT ;INIT NMLST PARAMS
MOVX T0,D%LSD ;set for list-directed
IORM T0,FLAGS(D)
MOVEM P1,TMPFLG ;[JLC] SAVE NAMELIST FLAG AC
POPJ P, ;[JLC]
%LDI: SKIPN IO.ADR ;[JLC] ANY I/O ADDR?
PJRST %SETAV ;[JLC] NO. RETURN TO USER PROG
MOVE P1,TMPFLG ;[JLC] GET NAMELIST FLAG AC
PUSHJ P,LDSET ;[JLC] SETUP VARIABLE PARAMS
PUSHJ P,NLMAIN ;[JLC] DO MAIN LOOP
MOVEM P1,TMPFLG ;[JLC] SAVE NAMELIST FLAG AC
SKIPN NLRP. ;[JLC] IF REPEAT COUNT GONE
TDNN P1,FINFLG ;[JLC] CHECK IF FINISHED
POPJ P, ;[JLC] JUST RETURN FOR MORE
SETZM %UDBAD ;[JLC] SETUP FOR NO MORE INPUT
PJRST %SETAV ;[JLC] RETURN TO USER PROG
;LIST-DIRECTED OUTPUT
;GETS A VARIABLE ADDRESS AND TYPE AND OUTPUTS THE VALUE
;IN THE PROPER FORMAT. IN ORDER TO AVOID A TRAILING COMMA,
;THE COMMA IS OUTPUT FIRST, BUT ONLY AFTER THE 1ST VALUE HAS BEEN
;WRITTEN
;* Warning - smashes Perm acs *
%LDOST: PUSHJ P,NLINIT ;INITIALIZE STUFF
MOVX T0,D%LSD ;Set for list-directed
IORM T0,FLAGS(D)
MOVEI T1,1 ;SET OUTPUT FOR 1PG
MOVEM T1,SCL.SV
PJRST CHKEND ;[JLC] CHECK FOR COL 1
%LDO: SKIPN IO.ADR ;[JLC] ANY I/O ADDR?
JRST LDODON ;[JLC] NO. GO OUTPUT REC
PUSHJ P,LDSET ;[JLC]SETUP VARIABLE PARAMS
PJRST NLMO ;[JLC] OUTPUT IT
LDODON: PUSHJ P,%ORECS ;[JLC] OUTPUT A RECORD
PJRST %SETAV ;[JLC] AND RETURN TO USER PROG
LDSET: MOVE T1,IO.ADR ;GET ADDRESS
MOVEM T1,NLADD. ;SAVE IT
HRRZ T1,IO.TYP ;GET VARIABLE TYPE
MOVEM T1,VARTYP ;SAVE IT
MOVE T1,IO.SIZ ;[JLC] GET SIZE OF ENTRY
MOVEM T1,NLSIZ. ;SAVE IT
MOVE T1,IO.INC ;GET INCR WORD
MOVEM T1,NLINC. ;SAVE OFFSET
MOVE T1,IO.NUM ;GET # LOCS
MOVEM T1,NLNUM. ;SAVE POSITIVE
POPJ P,
;NAMELIST INPUT - After finding the proper NAMELIST "Begin data"
;sequence ($ or & in column 2), the NAMELIST name in the data is
;matched against the NAMELIST required by the user's program. If it
;does not match, the input is scanned to the next "Begin data" sequence
;and matched again. Upon a match, we grab a variable name from the
;data, and search for it in the NAMELIST block to get the variable
;parameters. Then we look at whether the user has specified array
;indices in the data. If so, we calculate the array reference. If the
;variable is an array but no array indices are given, the number of
;elements in the array is used as the possible number of entries to
;fill, starting at the first array element. Note that before the data
;loop we clear NLNAM., which indicates to subroutine VARNAM to actually
;get a new variable name from the data. Under certain circumstances,
;we can return from NLMAIN with the next variable name left in NLNAM.
%NLI: PUSHJ P,%SAVE4 ;SAVE P1-P4
PUSHJ P,NLINIT ;INIT NMLST PARAMS
MOVE T0,FLAGS(D)
TXZ T0,D%IO ;0=INPUT
TXO T0,D%NML ;MEANS "=" & "(" ARE LOGIC DELIMS
MOVEM T0,FLAGS(D)
MOVX T1,NLEFLG ;END OF DATA FLAGS
MOVEM T1,FINFLG
MOVX T1,COMFLG+SPCFLG+ALFLAG+NLEFLG+NULFLG+ASTFLG+EOLFLG+EQUFLG+LPRFLG
;LEGAL DELIMITERS [3063]
MOVEM T1,LDLFLG ;FOR CHECKING AFTER A SCAN
MOVX T1,ALFLAG ;ALPHA CHAR ONLY BEGINS VARIABLE
MOVEM T1,NLVFC. ;SAVE FOR SCAN
MOVE T1,NLARG. ;GET NMLST PNTR
MOVE T1,(T1) ;GET NAMELIST NAME
MOVEM T1,NLVAL. ;SAVE IT
NLILP1: PUSHJ P,NLGETB ;GET BEG OF NAMELIST DATA
PUSHJ P,SKPCHR ;SKIP BEGIN CHAR
PUSHJ P,NLINAM ;GET NAMELIST NAME IN DATA
MOVE T2,NLNAM. ;GET NAME FOUND BY NLINAM
CAME T2,NLVAL. ;IS IT THE ONE WE WANT?
JRST NLILP1 ;NO
SETZM NLNAM. ;CLEAR VARIABLE NAME
NLILP2: PUSHJ P,VARNAM ;GET A VARIABLE NAME
TDNE P1,FINFLG ;END OF DATA?
JRST NLEND ;YES. LEAVE
SKIPN NLNAM. ;FIND ANYTHING?
JRST DOLFND ;NO. IT WAS AN ERROR, UNDOUBTEDLY
TDNE P1,FINFLG ;END OF DATA?
JRST NLEND ;YES. GO FIND END-OF-LINE
PUSHJ P,NLVSRH ;SEARCH IN NAMELIST TABLE
MOVE T1,NLNAM. ;Get name incase error
TXNN P1,NLSFLG ;FOUND?
; IOERR (VNN,799,309,?,Variable $S not in namelist,<T1>,%ABORT)
$ECALL VNN,%ABORT ;?Variable $S is not in namelist
PUSHJ P,CALARR ;YES. CALC ADDR & # ENTRIES
SETZM NLRP. ;CLEAR REPEAT COUNT
SETZM NLNAM. ;CLEAR VARIABLE NAME
SETZM NLFV. ;STARTING NEW VARIABLE
PUSHJ P,NLMAIN ;DO MAIN CODE
TDNN P1,FINFLG ;END OF DATA?
JRST NLILP2 ;NO
JRST NLEND ;YES
DOLFND: PUSHJ P,GTCHRL ;GET NEXT CHAR
TDNN P1,FINFLG ;END OF DATA?
JRST DOLFND ;NO. SCAN SOME MORE
NLEND: PJRST NLEOL ;LOOK FOR END OF LINE AND RETURN TO CALLER
;INITIALIZATION OF NAMELIST/LDIO PARAMETERS
NLINIT: MOVE T1,A.NML ;Get addr of arg block
SKIPN T.NML ;Indirect?
MOVE T1,(T1) ;YES.
; SKIPE T1,A.NML ;[3017] Get the addr of the arg block
; XMOVEI T1,@0(T1) ;[3017] Get the namelist address
MOVEM T1,NLARG. ;SAVE ARG LIST ADDR
SETZM NLSWRD ;Clear string count
SKIPN T1,NLSPTR ;Is there a string yet?
HRLZI T1,(POINT 7,) ;NO. load a 7 bit pointer
MOVEM T1,NLCPTR ;Initialize current input string ptr
SETZ P1, ;CLEAR FLAG WORD
SETZM NLRP. ;CLEAR REPEAT COUNT
SETZM NLFLG. ;CLEAR FLAG
SETZM CHRLST ;[3120]Clear flag
SETZM ENC.WD ;FREE FORMAT
SETZM ENC.W2 ;Clear 2nd word also [3057]
DSETZM SS.ADR ;Reset substring words [3063]
SETZM NLFV. ;SET NO VARIABLES FILLED
SETZM SCL.SV ;CLEAR SCALE FACTOR
SETZM VALTYP ;Clear input variable type [3063]
POPJ P,
;CALARR - CHECKS THE DIMENSIONALITY OF THE VARIABLE SPECIFIED
;IN THE DATA. IF IT IS AN ARRAY, IT CALLS CALADD, WHICH CHECKS FOR THE
;PRESENCE OF INDICES IN THE DATA. OTHERWISE IT JUST CHECKS FOR
;THE EQUAL-SIGN FOLLOWING THE VARIABLE NAME.
;SMASHES P2, P3, P4.
CALARR: PUSHJ P,VARSET ;SETUP VARIABLE PARAMS
PUSHJ P,NLNB ;SCAN FOR NON-BLANK
MOVE T0,VARTYP ;Get variable type [3063]
CAIE T0,TP%CHR ;Character? [3063]
JRST CALAR1 ;NO. [3063]
PUSHJ P,CALCHR ;Do character processing[3063]
JRST CALAR2 ;Skip non-char processing[3063]
CALAR1: SKIPE NLDIM. ;ARRAY? [3112]
PUSHJ P,CALADD ; YES. PROCESS INDICES IF ANY [3063]
CALAR2: TDNE P1,FINFLG ;LEAVE IF DONE [3063]
POPJ P,
CAIE T1,"=" ;DO WE HAVE =?
; IOERR (NEQ,799,513,?,Found "$C" when expecting "=",<T1>,%ABORT)
$ECALL NEQ,%ABORT
PJRST SKPCHR ;SKIP THE EQUAL SIGN
;VARSET - DOES ALL THE NECESSARY SETUP GIVEN THE POINTER
;INTO THE NAMELIST BLOCK FOR THE GIVEN VARIABLE (IN NLVAR.).
;[3063] We now check for new(V7)-style NAMELIST blocks. Old(V6)-style
; blocks had ARRAY-SIZE (number of elements) in the left-half
; and ARRAY-OFFSET in the right half of the third word of the
; block. New-style has ARRAY-SIZE in the third word and OFFSET
; in the fourth word. New-style blocks are indicated by "1"
; in bit zero of the second word, while old-style blocks
; have zero in bit zero (see diagram at the beginning of NMLST).
; To simplify things, ARRAY-SIZE and ARRAY-OFFSET are now stored
; in NLEMS. and NLOFF., respectively, during initialization.
VARSET: MOVEI T1,1 ;INITIALIZE # ENTRIES AT 1
MOVEM T1,NLNUM.
MOVE T2,NLVAR. ;GET THE ARG PNTR
MOVE T1,(T2) ;GET VARIABLE NAME
MOVEM T1,NLNAM. ;SAVE IT
LDB T1,[POINT 7,1(T2),8] ;GET # DIMS
MOVEM T1,NLDIM. ;SAVE # DIMS
JUMPE T1,VARST1 ;IT'S A SCALAR
SKIPL 1(T2) ;New style block?(ck 1st wd/ ARRAYNAME entry)
JRST OLDBLK ;NO
MOVE T1,2(T2) ;Get # entries in array
MOVEM T1,NLNUM. ;Save # array entries left
MOVEM T1,NLEMS. ;Save # total array entries
MOVE T1,3(T2) ;Get offset
MOVEM T1,NLOFF. ;Save offset
XMOVEI T1,4(T2) ;Get address if first factor
MOVEM T1,NLFCT. ;Save address of first factor
JRST VARST1 ;Back in line
OLDBLK: HLRZ T1,2(T2) ;GET # ENTRIES IN ARRAY
MOVEM T1,NLNUM. ;SAVE IT
MOVEM T1,NLEMS. ;Save # total array entries
HRRZ T1,2(T2) ;Get offset
MOVEM T1,NLOFF. ;Save offset
XMOVEI T1,3(T2) ;Address of first factor
MOVEM T1,NLFCT. ;Save address/first factor
VARST1: LDB T3,[POINT 4,1(T2),12] ;GET TYPE
MOVEM T3,VARTYP ;SAVE TYPE
NLTYP: CAIN T3,TP%CHR ;Character string?
JRST NLICHR ;YES. Go initialize for characters
XMOVEI T1,@1(T2) ;Get base addr
MOVEM T1,NLADD. ;SAVE IT
MOVE T1,%SIZTB(T3) ;GET SIZE
MOVEM T1,NLSIZ. ;SAVE SIZE
MOVEM T1,NLINC. ;AND OFFSET
POPJ P,
NLICHR: DMOVE T2,@1(T2) ;[]Load pointer & count
MOVEM T2,NLADD. ;[]Store it
MOVEM T2,IO.ADR ;[]For string comparisons
MOVEM T3,NLSIZ. ;[]Save length
MOVEM T3,NLINC. ;[]Save increment
POPJ P, ;[]All done
;CALADD - PROCESSES THE INDICES OF AN ARRAY REFERENCE.
;IF THERE ARE NO INDICES, IT GRABS THE ARRAY SIZE DIVIDED
;BY THE ENTRY SIZE TO GET THE # OF ENTRIES. IF THERE ARE INDICES,
;IT ADDS THE OFFSET CALCULATED TO NLADD.
;SMASHES P2,P3,P4
CALADD:
MOVE P2,NLVAR. ;GET VARIABLE ENTRY PNTR
CAIE T1,"(" ;LEFT PAREN?
POPJ P, ;[]NO. Entire array(all done)
MOVE P3,NLDIM. ;P3= # dims left to process
MOVE P4,NLFCT. ;P4 points to factors [3063]
XMOVEI T1,NLVAL. ;POINT TO VALUE
MOVEM T1,IO.ADR ;FOR %INTI
ADDLP1: PUSHJ P,%INTI ;GET AN INTEGER
MOVE T2,NLVAL. ;GET THE VALUE
IMUL T2,(P4) ;MULTIPLY BY A FACTOR
IMUL T2,NLSIZ. ;GET THE REAL OFFSET
ADDM T2,NLADD. ;ADD TO ADDRESS
PUSHJ P,NLSDEL ;GET THE NEXT DELIMITER
SOJLE P3,ADDLPD ;Go until no more dims
AOJA P4,ADDLP1 ;. .
ADDLPD: PUSHJ P,GETDEL ;GET THE DELIM
CAIE T1,")" ;END OF INDICES?
; IOERR (NRP,799,514,?,Missing right paren,,%ABORT)
$ECALL NRP,%ABORT
PUSHJ P,SKPCHR ;SKIP THE RIGHT PAREN
PUSHJ P,NLNB ;AND GO TO NEXT DELIM
;DON'T TOUCH T1 - CONTAINS DELIM
MOVN T2,NLOFF. ;Get negative offset [3063]
ADDB T2,NLADD. ;ADD INTO ADDR
XMOVEI T3,@1(P2) ;GET ORIG BASE ADDR
SUB T3,T2 ;GET NEG OFFSET TO DESIRED LOC
JUMPLE T3,OFFOK ;OK IF NEG OR ZERO
; IOERR (ILS,799,516,?,Illegal subscript,,%ABORT)
$ECALL ILS,%ABORT ;?Illegal subscript
OFFOK: IDIV T3,NLSIZ. ;GET NEG # ENTRIES IN OFFSET
MOVE T2,NLEMS. ;Get total entries in array [3063]
ADD T2,T3 ;GET # ENTRIES LEFT
MOVEM T2,NLNUM. ;SAVE IT
JUMPG T2,%POPJ ;OK IF .GT. ZERO
$ECALL ILS,%ABORT ;?Illegal subscript
;[3063]
;CALCHR: is the analog of CALADD. We process the indices of a character
; array reference, utilizing ADJBP to calculate the address of the
; referenced element. If the element is out of bounds, by virtue
; of beginning before the actual start of the array, or of being
; the nth +1 or greater element of the array, a fatal error has
; occurred. When we leave this routine, NLNUM. = the number of
; elements left in the array, including the one just identified.
; When all of the dimensions have been processed, and the element's
; address is known, we look for a substring identifier. If one
; is found, we process it and set SS.ADD = substring address,
; and SS.SIZ = substring size, else SS.ADR and SS.SIZ = zero.
CALCHR: DSETZM SS.ADR ;Reset substring indicator
SKIPN P3,NLDIM. ;Array? (P3=dimensions to process)
JRST ENDIMS ;NO. Go check for substring
MOVE P2,NLVAR. ;Get variable entry pointer
CAIE T1,"(" ;LEFT PAREN?
POPJ P, ;NO. ENTIRE ARRAY
MOVE P4,NLFCT. ;P4 points to factors
XMOVEI T1,NLVAL. ;POINT TO VALUE
MOVEM T1,IO.ADR ;FOR %INTI
SETZM IO.SIZ ;Initialize counter
ADCLP1: PUSHJ P,%INTI ;GET AN INTEGER
MOVE T2,NLVAL. ;Get value
IMUL T2,(P4) ;MULTIPLY BY A FACTOR
ADDM T2,IO.SIZ ;Count it
PUSHJ P,NLSDEL ;GET THE NEXT DELIMITER
SOSLE P3 ;Done if no more dimensions
AOJA P4,ADCLP1 ;Go add in next factor
ADCLPD: PUSHJ P,GETDEL ;GET THE DELIM
CAIE T1,")" ;Proper delimiter of indices?
$ECALL NRP,%ABORT ; "? Missing right paren"
PUSHJ P,SKPCHR ;SKIP THE RIGHT PAREN
PUSHJ P,NLNB ;AND GO TO NEXT DELIM
;DON'T TOUCH T1 - CONTAINS DELIM
MOVN T2,NLOFF. ;Get negative offset
ADDB T2,IO.SIZ ;Calculate real offset
SKIPGE T2 ;OK if positive
$ECALL ILS,%ABORT ;"Illegal subscript"
ADJBP T2,NLADD. ;Adjust the pointer
MOVEM T2,NLADD. ;Store new pointer
MOVN T2,IO.SIZ ;Negative offset
IDIV T2,NLSIZ. ;Calc elements
ADDB T2,NLNUM. ;Calc elements left
JUMPG T2,ENDIMS ;OK if .GT. zero
$ECALL ILS,%ABORT ;"? Illegal subscript"
ENDIMS: TDNN P1,FINFLG ;[]LEAVE IF DONE
CAIE T1,"(" ;Is there sub-string info?
POPJ P, ;NO
PUSHJ P,SKPCHR ;Skip "("
SUBSTR:
XMOVEI T1,NLVAL. ;Point to value
MOVEM T1,IO.ADR ;For %INTI
MOVEI T2,1 ;Assume character position 1
MOVEM T2,NLVAL. ;Store default position
PUSHJ P,NLNB ;Get next non-blank
CAIN T1,":" ;Null value?
JRST SUB1 ;YES.
PUSHJ P,%IBACK ;Point to beginning
PUSHJ P,%INTI ;Get the 1st character position
MOVE T1,NLSIZ. ;Full element size
EXCH T1,NLVAL. ;Assume substring runs to last char
CAMLE T1,NLVAL. ;First character within element?
$ECALL ISS,%ABORT ;"Illegal substring descriptor"
SOSGE T1 ;Relative character position > zero?
$ECALL ISS,%ABORT ;"Illegal substring descriptor"
MOVNM T1,SS.SIZ ;Save (NEG) 1ST char relative position
ADJBP T1,NLADD. ;Substring pointer
MOVEM T1,SS.ADR ;Store substring pointer
PUSHJ P,GETDEL ;Get the delimiter
CAIE T1,":" ;Is it the right one?
$ECALL NEC,%ABORT ;"? Got $C when expecting ":""
SUB1: PUSHJ P,SKPCHR ;Skip ":"
PUSHJ P,NLNB ;Get the next delimiter
CAIN T1,")" ;End of substring descriptor?
JRST SUB2 ;YES.
PUSHJ P,%IBACK ;Backup for %INTI
PUSHJ P,%INTI ;Get ending character position
SUB2: MOVE T1,NLVAL. ;Load last character position
CAMLE T1,NLSIZ. ;Character position within element?
$ECALL ISS,%ABORT ;"? Illegal substring descriptor"
ADDB T1,SS.SIZ ;Calculate substring length
SKIPG T1 ;Positive length?
$ECALL ISS,%ABORT ;"? Illegal substring descriptor"
PUSHJ P,GETDEL ;Get the delimiter
CAIE T1,")" ;Is it the right one?
$ECALL NRP,%ABORT ;"? Missing right paren"
PUSHJ P,SKPCHR ;Skip right paren
PJRST NLNB ;Get next delimiter and return
SEGMENT DATA
SS.ADR: BLOCK 1
SS.SIZ: BLOCK 1
SEGMENT CODE
;VARNAM & NLINAM - ASSEMBLES A VARIABLE NAME OR NAMELIST
;NAME FROM THE DATA. IF A NAME ALREADY EXISTS IN NLNAM., JUST RETURNS
VARNAM: SKIPE NLNAM. ;IF IT WAS NON-ZER
POPJ P, ;IT WAS A BAD LOGIC VALUE
NLINAM: SETZM NLNAM. ;CLEAR NAME
SKIPE DLFLG. ;ARE WE AT END OF PREVIOUS DATA SCAN?
PUSHJ P,NLSDEL ;YES. SCAN FOR THE DELIMITER
PUSHJ P,NLNB ;GET NON-BLANK CHAR
TDNE P1,FINFLG ;END OF DATA?
POPJ P, ;YUP
SKIPE NLFLG. ;ERROR IF NULL ENTRY (COMMA FOUND)
TDNN P1,NLVFC. ;MUST BEGIN WITH ALPHA
; IOERR (ILN,799,515,?,Variable or namelist does not start with letter,,%ABORT)
$ECALL ILN,%ABORT
MOVEI P2,6 ;6 CHARS TOTAL
SKIPA P3,[POINT 6,NLNAM.] ;SIXBIT PNTR, ALREADY GOT 1ST CHAR
NLINL1: PUSHJ P,GETCHR ;GET NEXT CHAR
TXNN P1,ALFLAG+DIGFLG ;ALPHA OR DIGIT?
POPJ P, ;NO. RETURN
CAIL T1,140 ;CONVERT TO SIXBIT
SUBI T1,40
SUBI T1,40
IDPB T1,P3 ;SAVE IT
SOJG P2,NLINL1 ;MAX 6 CHARS
; PJRST NLNA ;THEN SCAN FOR NON-ALPHAMERIC
;SCAN FOR NON-ALPHAMERIC
NLNA: PUSHJ P,GETCHR ;GET A CHAR
TXNE P1,ALFLAG+DIGFLG ;ALPHA OR DIGIT?
JRST NLNA ;YES. SKIP IT
POPJ P, ;NO. RETURN
;NLVSRH - SEARCH FOR A VARIABLE NAME IN THE NAMELIST
;BLOCK. THE NUMBER OF ENTRIES TAKEN BY A VARIABLE IN THE NAMELIST
;BLOCK IS DEPENDENT ON ITS DIMENSIONALITY.
NLVSRH: TXZ P1,NLSFLG ;CLEAR SEARCH FOUND FLAG
MOVE T3,NLARG. ;GET THE ARG PNTR
ADDI T3,1 ;POINT TO 1ST VARIABLE
NLVLP1: SKIPE T1,(T3) ;GET VARIABLE NAME
CAMN T1,FINCOD ;0 OR END CODE IS END
POPJ P, ;RETURN IF END OF LIST
CAMN T1,NLNAM. ;VARIABLE WE WANT?
JRST NLVFND ;YES!
LDB T2,[POINT 7,1(T3),8] ;NO, GET # DIMS
ADDI T3,2 ;ASSUME SCALAR
JUMPE T2,NLVLP1 ;BACK IF SCALAR
SKIPGE -1(T3) ;Size and offset in half-words?[3063]
AOJ T3, ;NO. block is one word longer [3063]
ADDI T3,1(T2) ;MORE JUNK IF ARRAY
JRST NLVLP1
NLVFND: TXO P1,NLSFLG ;SET FOUND FLAG
MOVEM T3,NLVAR. ;SAVE PNTR
POPJ P,
;NLMAIN - THIS IS THE MAIN NAMELIST AND LIST-DIRECTED I/O
;ROUTINE. USING THE VARIABLE PARAMETERS SET UP FOR IT
;(NLADD.,NLSIZ.,NLINC.,NLNUM.) IT SCANS FOR A VALUE AND
;REPEAT COUNT IF THE REPEAT COUNT IS ZERO, DOES THE
;APPROPRIATE VALUE CONVERSION, STORES THE VALUE FOUND
;INTO THE USER'S VARIABLE (OR ARRAY ENTRY), AND DOES ALL
;THE APPROPRIATE INCREMENTING AND DECREMENTING OF THE
;VARIABLE PARAMETERS AND REPEAT COUNT.
;
;If the destination variable is of type character, jump to
;VARCHR to perform byte-string instructions, and to check
;whether pointers are set to beginning of repeated string.
;As before, non-character variables will be filled from
;Hollerith strings, with each loop through NLP picking up
;the next five (single precision) or ten (double precision)
;bytes from the input string. The string has been padded
;with sufficient spaces (maximum of 9) to allow creation
;of a single or double precision variable via a MOVE-MOVEM
;or DMOVE-DMOVEM instruction pair. These spaces are not
;included in the string count. When the string is
;exhausted, the pointers are reset to the beginning of the
;string, and if the repeat count is not zero, the next
;destination variable (if non-character) will be filled
;using the current string.
NLMAIN:
NLP: SKIPN NLRP. ;REPEAT COUNT?
NLVAL: PUSHJ P,NLSCV ;NO. GET VALUE & REPEAT COUNT
SKIPGE T1,NLFLG. ;DID WE GET A VALUE?
POPJ P, ;NO. LEAVE
JUMPE T1,FULVAL ;JUST DECR REPEAT COUNT IF NULL
MOVE T1,VARTYP ;GET VARIABLE TYPE
CAIN T1,TP%CHR ;Type character?
JRST VARCHR ;YES. special processing
CAME T1,CNVTYP ;DID WE CONVERT YET?
PUSHJ P,NLACNV ;NO. CONVERT TO DESIRED FORMAT
DMOVE T1,NLCVL. ;LOAD THE VALUE
MOVE T3,NLSIZ. ;MAKE SURE WE STORE IT RIGHT
XCT NLSTOR(T3)
FULVAL: SETOM NLFV. ;FILLED A VARIABLE
PUSHJ P,NLRPI ;PROCESS VALUE PNTR/COUNTS
MOVE T1,NLINC. ;INCR ARRAY POINTER
ADDM T1,NLADD.
SOSLE NLNUM. ;DECR COUNT
JRST NLP ;LOOP IF MORE
POPJ P,
;NLSTOR - A LITTLE TABLE USED TO STORE THE FINAL VALUES
;INTO THE USER'S VARIABLES. IT IS INDEXED BY THE ENTRY SIZE
;(EITHER 1 OR 2) EXTRACTED FROM %SIZTB. THIS WILL ABSOLUTELY
;NOT WORK FOR A KA-10!!!
NLSTOR: JFCL
MOVEM T1,@NLADD.
DMOVEM T1,@NLADD.
;VARCHR:
;Variables of type character, however, use one string per
;destination variable. VARCHR resets NLCPTR and NLCWRD,
;decrements NLRP. if the preceding variable did not exhaust
;the string, and if NLRP. is zero, loops back to NLVAL to
;get another value. When VARCHR has an appropriate value,
;it moves the string and jumps back in line. NLRPI has
;been taught to reset the pointers and decrement NLRP.
;for each destination variable of type character.
VARCHR: MOVE T1,NLSWRD ;Beginning word count
CAME T1,NLCWRD ;Are we in the middle of a string?
PUSHJ P,RSTPTR ;YES. Reset ptr and decr repeat count
SKIPN NLRP. ;Still repeat count?
JRST NLVAL ;NO. Go input another variable
MOVE T1,VALTYP ;Get input variable type
CAIE T1,TP%LIT ;Input type literal?
$ECALL SNQ,%ABORT ;"? String not within single quotes"
MOVE T0,NLSBYT ;Source string count
MOVE T1,NLSPTR ;Source byte pointer
SKIPN T3,SS.SIZ ;Is it a substring? [3063]
MOVE T3,NLSIZ. ;NO.
SKIPN T4,SS.ADR ;Is it a substring? [3063]
MOVE T4,NLADD. ;NO.
EXTEND T0,[MOVSLJ
" "] ;Move the string with space fill
TRNN ;Ignore truncation (NO-OP)
SETOM NLFV. ;FILLED A VARIABLE
PUSHJ P,NLRPI ;PROCESS VALUE PNTR/COUNTS
SOSG NLNUM. ;Any more elements?
POPJ P, ;NO...quit
DSETZM SS.ADR ;Reset substring stuff [3063]
MOVE T1,NLINC. ;Get array increment
ADJBP T1,NLADD. ;Adjust destination byte pointer
MOVEM T1,NLADD. ;Store new pointer
JRST NLP ;Loop thru next element
;NLSCV - NAMELIST AND LDIO SCAN FOR A VALUE
;
;THIS ROUTINE SCANS FOR A VALUE AND REPEAT COUNT
;IT BEGINS ITS SCAN IN DOUBLE PRECISION, SO THAT NO
;PRECISION WILL BE LOST IF SOMEWHERE TOWARD THE END OF
;A LIST WE FIND A VARIABLE WHICH IS DOUBLE PRECISION
;WHICH IS STILL COVERED BY A DATA REPEAT COUNT.
;IF "*" FOUND AS DELIMITER, SET THE REPEAT COUNT,
;AND SCAN AGAIN IN DOUBLE PRECISION.
;IF "*" NOT FOUND, SET REPEAT COUNT TO 1 AND RETURN WITH
;VALUE=VALUE FOUND.
NLSCV: SETZM NLRP. ;CLEAR THE REPEAT COUNT
SETZM VALTYP ;Clear input variable type
MOVEI T1,TP%DPR ;SCAN FIRST FOR D.P.
MOVEM T1,TOTYPE
MOVEI T1,1 ;SET REPEAT COUNT TO 1
MOVEM T1,NLRP. ;MIGHT FILL NLRP. IN SETNUL
PUSHJ P,NLSCAN ;SCAN FOR VALUE
SKIPG NLFLG. ;LEAVE IF END DATA OR NULL
POPJ P, ;OH, WELL
PUSHJ P,NLSDER ;NO. GET THE DELIMITER
CAIE T1,"*" ;REPEAT COUNT?
POPJ P, ;NO. LEAVE
MOVE T1,VALTYP ;GET THE VALUE TYPE
CAIN T1,TP%DPR ;DOUBLE REAL?
SKIPE IO.INF ;YES. ANY "." OR EXPONENT
JRST RPERR ;NOT REAL OR DOT/EXP FOUND
MOVEI T1,TP%INT ;YES. CONVERT TO INTEGER
MOVEM T1,TOTYPE
PUSHJ P,NLCNV ;DO THE CONVERSION
MOVE T1,NLCVL. ;GET THE CONVERTED VALUE
JUMPL T1,RPERR ;ERROR IF NEGATIVE
MOVMM T1,NLRP. ;SAVE THE REPEAT COUNT
MOVEI T1,TP%DPR ;D.P. AGAIN
MOVEM T1,TOTYPE ;Set acceptable input type
PUSHJ P,SKPCHR ;SKIP THE *
SETZM NLFV. ;DON'T SKIP A COMMA
PJRST NLSCAN ;GO GET NEXT VALUE
;THE FOLLOWING CODE SHOULD BE SUBSTITUTED FOR
; PUSHJ P,SKPCHR
; PJRST NLSCAN
;ABOVE, IFTHE ANSI COMMITTEE DECIDES EVENTUALLY THAT 3*<BLANK>4 SHOULD
;BE READ AS 3*,4 (3 NULL VALUES, THEN A 4). AS OF NOW, THE
;COMMITTEE'S PRELIMINARY DECISION HAS BEEN TO ALLOW BOTH
;INTERPRETATIONS. MUCH OF THE INDUSTRY, AS WELL AS
;PDP-11 AND VAX FORTRAN-77, READ THE BLANK AS A VALUE SEPARATOR,
;AND, THEREFORE, AS 3*,4.
REPEAT 0,<
PUSHJ P,GETCHR ;GET THE NEXT CHAR
PUSHJ P,CHKDLM ;CHECK FOR NON-BLANK CHAR
PJRST NLSCAR ;AND GET THE VALUE
>;END REPEAT 0
RPERR: ;IOERR (RPE,799,521,?,Illegal repeat count,,%ABORT)
$ECALL RPE,%ABORT
;NLSCAN - SCAN FOR AN INDIVIDUAL VALUE
;CNVTYP IS SET FOR NO CONVERSION DONE YET, SO THAT THE TEST IN
;NLMAIN WILL FORCE A CONVERSION TO THE APPROPRIATE TYPE.
;THE FIRST CHARACTER OF DATA IS CHECKED FOR ITS VALIDITY
;BY MATCHING ITS ASSOCIATED FLAG (IN P1) AGAINST THE "VALID FIRST CHARACTER
;FLAG LIST" (NLFLST). IF THERE IS NO MATCH, IT IS EITHER A BAD CHARACTER
;IN DATA OR THE BEGINNING OF THE NEXT VARIABLE NAME (NAMELIST ONLY).
;THAT TEST IS DONE BY SETNUL.
NLSCAN: SKIPE DLFLG. ;ARE WE AT END OF PREVIOUS DATA SCAN?
PUSHJ P,NLSDEL ;YES. SCAN FOR THE DELIMITER
PUSHJ P,NLNB ;GET NEXT NON-BLANK CHAR
NLSCAR: SETOM CNVTYP ;SET NO CONVERSION DONE YET
SKIPG NLFLG. ;NON-NULL VALUE FOUND?
POPJ P, ;NO. LEAVE
NLSCN1: PUSHJ P,SGNTST ;TEST FOR SIGN
MOVEI T2,NLFLST ;GET FLAG LIST FOR SCAN
PUSHJ P,NLFSRH ;SCAN THE LIST
TXNN P1,NLSFLG ;FOUND?
JRST SETNUL ;NO. TRY FOR NEW VARIABLE
MOVEI P2,(T2) ;COPY INDEX TO TABLES
PUSHJ P,%IBACK ;MOVE PNTR BACK TO 1ST CHAR
DSETZM NLVAL. ;INIT LOW VALUE WORDS
SETOM DLFLG. ;SET FLAG TO SCAN FOR DELIM
XMOVEI T1,NLVAL. ;GET ADDR TO STORE RESULT
MOVEM T1,IO.ADR ;SAVE IT
MOVE T1,NLTYPE(P2) ;GET TYPE
MOVEM T1,VALTYP ;SAVE IT
CAIN T1,TP%DPR ;IS IT DOUBLE REAL?
SETZ T1, ;YES. GIVE 0 SO FLIRT WON'T CONVERT
MOVEM T1,IO.TYP ;SAVE TYPE FOR I/O ROUTINE
XCT T1,NLSUB(P2) ;DO READ
PUSHJ P,GETDEL ;GET THE DELIMITER, SET FLAGS
TDNE P1,LDLFLG ;LEGAL DELIMITER AT END OF SCAN?
POPJ P, ;YES
$ECALL ILC,%ABORT ;NO. ILLEGAL CHAR
;CHECK FOR THE VALIDITY OF THE PRESENCE OF A VARIABLE NAME.
;THIS IS THE ONLY PLACE IN THE CODE WHERE WE HAVE TO CHECK EXPLICITLY
;WHETHER WE ARE DOING NAMELIST OR LIST-DIRECTED I/O. A VARIABLE NAME
;IN THE DATA IS CLEARLY ILLEGAL IN LIST-DIRECTED I/O, AND IS ILLEGAL
;IF IT FOLLOWS DIRECTLY AFTER THE LAST "VARIABLE=" SEQUENCE, THAT IS,
;BEFORE A VARIBLE HAS BEEN FILLED WITH ANY DATA.
;WE USE A SPECIAL LOCATION - NLVFC. (NAMELIST VARIABLE 1ST CHAR)
;WHICH HAS THE FLAGS ALLOWED FOR THE FIRST CHARACTER OF A VARIABLE.
;FOR NAMELIST, THIS IS SET TO "ALFLAG" TO INDICATE THAT VARIABLE
;NAMES MUST START WITH ALPHABETIC CHARACTERS. IT IS SET TO
;ZERO FOR LIST-DIRECTED I/O TO INDICATE THAT VARIABLE NAMES ARE
;NOT ALLOWED FOR LIST-DIRECTED I/O.
;IF EVERYTHING IS LEGAL, THE REST OF THE DATA IS SET TO NULL,
;THAT IS, THE DATA FLAG IS SET TO ZERO (INDICATING A NULL) AND THE
;DATA REPEAT COUNT IS SET TO THE LEFTOVER ARRAY ENTRY COUNT.
SETNUL: TDNE P1,NLVFC. ;THIS CHARACTER ALLOWED?
SETNL1: SKIPN NLFV. ;VARIABLE FILLED YET?
$ECALL ILC,%ABORT ;"ILLEGAL CHARACTER IN DATA"
SETZM NLFLG. ;SET FLAG FOR NULL VALUE
SETZM NLNUM. ;[2037] NO ELEMENTS LEFT
SETZM NLRP. ;[2037] NO REPEAT COUNT YET.
POPJ P,
;SIGN TEST - ACCUMULATES THE SIGN IN FRONT OF A DATA ELEMENT
;AND STUFFS IT AWAY IN NLSGN. ALTHOUGH THE ANSI STANDARD DOESN'T
;ALLOW IT, WE HERE ALLOW MULTIPLE SIGNS (AND DO THE "APPROPRIATE"
;THING, SO THAT --++--- COMES OUT JUST A SINGLE MINUS).
;HOWEVER, IS IS QUITE IMPORTANT THAT A TEST BE PERFORMED AFTER
;A SIGN IS FOUND - THAT A VALID CHARACTER IS FOUND AFTER IT
;FOR THE FIRST CHARACTER OF DATA. SO WE CALL NLFSRH WITH
;THE VALID CHARACTER FLAG LIST, AND GIVE AN ERROR IF THERE IS
;NO CHARACTER FLAG MATCH.
SGNTST: SETZM NLSGN. ;+=0, -=-1
TXNN P1,SGNFLG ;IS THE CHAR A SIGN?
JRST SGNEND ;NO. MOVE BACK PNTR
SGNLP: CAIN T1,"-" ;IS IT A MINUS?
SETCMM NLSGN. ;YES. NEGATE THE SIGN
PUSHJ P,GETCHR ;SKIP THE CHAR
PUSHJ P,NLNBER ;GET THE NEXT NON-BLANK
SKIPG NLFLG. ;NULL VALUE?
; IOERR (SNV,799,522,?,Sign with null value,,%ABORT)
$ECALL SNV,%ABORT
TXNE P1,SGNFLG ;ANOTHER SIGN?
JRST SGNLP ;YES. GO TEST IT
MOVEI T2,NLFLST ;NO. CHECK IN VALID DATA LIST
PUSHJ P,NLFSRH
TXNN P1,NLSFLG ;MATCH?
$ECALL SNV,%ABORT ;Sign with null value
SGNEND: POPJ P,
;NLFSRH - FLAG MATCH SEARCH - THIS SEARCHES A LIST OF
;FLAGS (ADDR SPECIFIED IN T2) FOR A MATCH (LOGICAL
;INTERSECTION) WITH THE FLAGS IN P1, AND PROVIDES THE MATCHING
;INDEX.
NLFSRH: MOVEI T3,(T2) ;SAVE THE LIST PNTR
NLFLP: SKIPN (T2) ;DONE WITH LIST?
JRST NLNFND ;YES. LEAVE
TDNN P1,(T2) ;NO. FLAG MATCH?
AOJA T2,NLFLP ;NO. TRY AGAIN
TXO P1,NLSFLG ;YES. SET FOUND FLAG
NLNFND: SUBI T2,(T3) ;GET RELATIVE INDEX
POPJ P,
;NLCNV - VALUE CONVERSION ROUTINE
;DECIDES WHICH CONVERSION TO DO BY RETRIEVING A CONVERSION
;TABLE ADDR INDEXED BY THE VALUE TYPE, THEN SEARCHES IN THE
;TABLE FOR THE VARIABLE TYPE, AND CALLS THE CORRESPONDING
;CONVERSION ROUTINE.
;NOTE THAT FOR MOST OF THE VALUE/VARIABLE TYPES, WE SIGNAL
;THAT THE CONVERSION HAS BEEN DONE BY PLACING THE CONVERTED TYPE
;IN CNVTYP. FOR ALPHAMERIC CONSTANTS, THIS CANNOT BE DONE, SINCE
;STRING DATA HAS A DIFFERENT SOURCE/REPEAT COUNT MECHANISM THAN
;THE THE OTHER DATA TYPES.
NLACNV: SKIPN T1,VARTYP ;RECORD VARIABLE TYPE
MOVEI T1,TP%INT ;DEFAULT IS INTEGER
MOVEM T1,TOTYPE
NLCNV: MOVE T2,TOTYPE ;GET TYPE DESIRED
CAMN T2,CNVTYP ;SAME AS LAST CONV?
POPJ P, ;YES. FORGET IT
DSETZM NLCVL. ;INIT CONVERTED VALUES
MOVE T3,VALTYP ;GET VALUE TYPE
CAIE T3,TP%LIT ;DON'T SIGNAL CONV IF ALPHA
MOVEM T2,CNVTYP ;BUT DO IF ANYTHING ELSE
MOVE T1,CNVLST(T3) ;GET CONVERSION LIST ADDR/COUNT
JUMPGE T1,BADCNV ;NO CONVERSION!
CNVLP: HLRE T2,(T1) ;GET A "TO" TYPE
JUMPL T2,GOTCNV ;A MATCH IF NEGATIVE
CAME T2,TOTYPE ;DESIRED TYPE?
AOBJN T1,CNVLP ;NO. TRY AGAIN
JUMPGE T1,BADCNV ;A LOSER IF TABLE GONE
GOTCNV: HRRZ T1,(T1) ;GET THE CONV ADDR
PUSHJ P,(T1) ;DO THE CONVERSION
SKIPL NLSGN. ;WAS IT MINUS?
POPJ P, ;NO
DMOVN T1,NLCVL.
DMOVEM T1,NLCVL. ;YES. SAVE IT NEGATIVE
POPJ P,
;NLNB - SCAN FOR NON-BLANK
;SKIPS BLANK-TYPE CHARS, RETURNS ON ANY OTHER CHARACTER
;(EXCEPT SKIPS END-OF-LINE ALTOGETHER)
;RETURNS -1 IF END OF DATA, 0 IF NULL, & 1 IF
;NON-NULL
NLNB: PUSHJ P,GETDEL ;GET CURRENT CHAR
SKIPE NLFV. ;DON'T SKIP FIRST COMMA
TXNN P1,COMFLG ;COMMA TO SKIP?
TXNE P1,EOLFLG ;ARE WE AT EOL?
PUSHJ P,SKPCHR ;YES. SKIP IT
SETZM DLFLG. ;CLEAR SCAN FOR DELIM FLAG
SETOM NLFLG. ;SET FLAG FOR EOF
JRST NLNB1 ;Go to loop, got first character
NLNB0: PUSHJ P,GTCHRL ;Get next char, skip eor
NLNB1: PUSHJ P,BERSCN ;Process character
POPJ P, ;Done, return
JRST NLNB0 ;Loop until done.
;NLNBER - SPECIAL SCAN FOR USE WITH THE REPEAT COUNT.
;THIS SCAN IS LIKE NLNB, BUT IT STOPS
;AT END OF RECORD (THAT IS, IT USES GETCHR INSTEAD OF GTCHRL).
NLNBER: SETZM DLFLG. ;CLEAR THE SCAN FOR DELIM FLAG
SETOM NLFLG. ;SET FLAG FOR EOF
PUSHJ P,GETDEL ;GET LAST DELIM
JRST NLNBR1 ;Already got first char.
NLNBR0: PUSHJ P,GETCHR ;Get character, possibly EOL
NLNBR1: PUSHJ P,BERSCN ;Process character
POPJ P, ;Done, return
JRST NLNBR0 ;Loop
;Return .+1 if done, .+2 if need more characters.
BERSCN: TDNE P1,FINFLG ;EOF OR END OF DATA?
POPJ P, ;YES. LEAVE
TXNN P1,COMFLG+EOLFLG ;COMMA OR EOL?
JRST NOTCEL ;NO
SETZM NLFLG. ;SET FOR COMMA OR EOR
POPJ P,
NOTCEL: TXNE P1,SPCFLG+NULFLG ;SPACE OR TAB OR NULL?
JRST %POPJ1 ;Yes, skip them
MOVEI T2,1 ;NO. SET FLAG FOR DATA
MOVEM T2,NLFLG.
POPJ P,
;NLEOL - SCAN FOR END OF RECORD (OR END OF FILE)
NLEOL: PUSHJ P,GETCHR ;GET A CHAR
TXNN P1,EOLFLG ;GO UNTIL EOL
JRST NLEOL
JRST %SETAV ;Reset & return
;CHKDLM - CHECKS THE DELIMITER WE ARE CURRENTLY LOOKING AT
;AND TREATS IT LIKE WE WERE DOING A FULL SCAN, SETTING NLFLG.
;TO -1 IF END DATA, ZERO IF NULL, SPACE, EOL, OR COMMA, AND
;+1 IF OTHER CHAR
CHKDLM: SETOM NLFLG. ;INIT FOR END OF DATA
TDNE P1,FINFLG ;END OF DATA?
POPJ P, ;YES. LEAVE
SETZM NLFLG. ;NO. PREPARE FOR NULL ITEM
TXNN P1,COMFLG+SPCFLG+NULFLG ;NULL ITEM?
AOS NLFLG. ;NO. SET FOR NON-NULL
POPJ P,
;NLSDEL - SCAN FOR A DELIMITER
;STARTS SCANNING WITH THE CURRENT CHAR (VIA GETDEL).
NLSDEL: PUSHJ P,GETDEL ;GET CURRENT CHAR
TXNE P1,EOLFLG ;ARE WE AT EOL?
PUSHJ P,SKPCHR ;YES. SKIP TO NEXT LINE
SETZM DLFLG. ;CLEAR SCAN FOR DELIM FLAG
JRST NLSDL1 ;Go start loop
NLSDL0: PUSHJ P,GTCHRL ;Get a character [3063]
NLSDL1: TDNN P1,FINFLG ;EOF OR END OF DATA?
TXNE P1,COMFLG ;OR COMMA
POPJ P, ;YES. LEAVE
TXNE P1,SPCFLG+NULFLG ;SPACE OR TAB OR NULL?
JRST NLSDL0 ;YES. SKIP IT
POPJ P,
;NLSDER - SCANS FOR A DELIMITER, BUT STOPS AT END OF RECORD
NLSDER: PUSHJ P,GETDEL ;GET THE LAST DELIM
NLSDRL: TDNN P1,FINFLG ;EOF OR END OF DATA?
TXNE P1,EOLFLG ;END OF RECORD?
POPJ P, ;YES. LEAVE
TXNE P1,COMFLG+EOLFLG ;OR, COMMA OR EOL?
JRST DELOFF ;YES. GOT DELIM
TXNN P1,SPCFLG+NULFLG ;SPACE OR TAB OR NULL?
JRST DELOFF ;NO. GOT DELIM
PUSHJ P,GETCHR ;Get character, (could get eol)
JRST NLSDRL ;Loop
DELOFF: SETZM DLFLG. ;CLEAR SCAN FOR DELIM FLAG
POPJ P,
;NLGETB - GET THE BEGINNING OF THE NAMELIST - ALL
;NAMELIST DATA SHOULD BEGIN WITH A "$" OR "&" IN COLUMN 2
;OF THE "CARD" (IBM STRIKES AGAIN!).
NLGETB: PUSHJ P,%RIPOS ;GET CURRENT POSITION
CAILE T1,2 ;WILL NEXT CHAR BE COL 2 OR LESS?
JRST GTNREC ;NO. GET NEXT RECORD
MOVEI T1,2 ;GET FROM POSITION 2
PUSHJ P,%SIPOS ;SET IT
PUSHJ P,GETCHR ;GET IT
TXNE P1,NLEFLG ;NAMELIST BEG/END FLAG?
POPJ P, ; YUP
GTNREC: PUSHJ P,%IRECS ;NO. GO TO NEXT LINE
JRST NLGETB ;NO
;GETDEL - GETS THE CURRENT CHARACTER AND GOES TO SET THE FLAGS
;ASSOCIATED WITH THAT CHARACTER.
;
;GETCHR - GETS THE NEXT CHARACTER AND GOES TO SET FLAGS.
GETDEL: PUSHJ P,%RIPOS ;GET INPUT POSITION
CAIG T1,1 ;AT COLUMN 1?
JRST GETCHR ;YES. THERE IS NO PREVIOUS CHAR
PUSHJ P,%IBYTC ;GET CURRENT CHAR
JRST NLTST ;GO TEST IT
GETCHR:
IFN FTNLC1,<
MOVE T0,FLAGS(D)
TXNN T0,D%NML ;THIS TEST ONLY IF NMLST
JRST GTCLSD ;NOT
PUSHJ P,%RIPOS ;GET CHAR POS
CAIGE T1,2 ;SKIP IF .GE. 2
PUSHJ P,%IBYTE ;GET A CHAR
> ;END FTNLC1
GTCLSD: PUSHJ P,%IBYTE ;GET A CHAR
NLTST: SETZ P1, ;CLEAR FLAGS
SKIPGE IRCNT(D) ;END OF LINE?
TXO P1,EOLFLG ;YES. SET FLAG
NLNEOF: JUMPE T1,NULFST ;SET NULL FLAG IF NULL
CAIN T1,11 ;TAB CHAR?
TXO P1,SPCFLG ;YES. SET SPACE FLAG
CAIGE T1,40 ;CONTROL CHAR?
POPJ P, ;YES. LEAVE
CAIG T1,100 ;COULD IT BE ALPHA?
JRST NOTALP ;NO
CAIG T1,"z" ;UPPER OR LOWER ALPHA?
CAIGE T1,"a"
CAIG T1,"Z"
CAIGE T1,"A"
POPJ P, ;NO
TXO P1,ALFLAG ;YES. SET FLAG
CAIE T1,"T" ;T OR F SETS LOGFLG
CAIN T1,"t"
TXO P1,LOGFLG
CAIE T1,"F"
CAIN T1,"f"
TXO P1,LOGFLG
POPJ P,
NOTALP: TDOA P1,NLCFLG-40(T1) ;SET CHAR FLAG
NULFST: TXO P1,NULFLG ;SET NULL FLAG
POPJ P,
;GTCHRL - GETS THE NEXT CHARACTER, AUTOMATICALLY GOING ON
;TO THE NEXT RECORD IF END-OF-RECORD IS REACHED.
;
;SKPCHR - IDENTICAL ENTRY TO GTCHRL, USED FOR ITS MNEMONIC VALUE
SKPCHR:
GTCHRL: SKIPLE IRCNT(D) ;END OF RECORD ALREADY?
JRST GTCHR1 ;NO. Go get a character
PUSHJ P,%IRECS ;YES. GET NEXT LINE
MOVE T0,FLAGS(D) ;Get flags
TXNN T0,D%NML ;Is this a NAMELIST request?
JRST GTCHR1 ;NO
MOVE T0,VALTYP ;Get input value type
CAIE T0,TP%LIT ;Are we in a character string?
JRST GTCHR1 ;NO. Proceed as always
; IS NEXT CHECK REALLY NECESSARY?
PUSHJ P,GETCHR ;Get the first character
TDNE P1,FINFLG ;SAME
POPJ P, ; CHECKS
TXNE P1,EOLFLG ; AS AT
JRST NULCHR ; "TESTL"
CAIE T1," " ;Real character; is it a space?
POPJ P, ;NO, return with this character
GTCHR1: PUSHJ P,GETCHR ;GET A CHAR
TESTL: TDNE P1,FINFLG ;END OF DATA?
POPJ P, ;YES. LEAVE
TXNE P1,EOLFLG ;END OF LINE?
JRST NULCHR ;Yes, return a null char
JUMPE T1,GTCHRL ;SKIP IT IF NULL
POPJ P,
NULCHR: MOVX P1,NULFLG ;[]CREATE A NULL
SETZ T1, ;RETURN A NULL
POPJ P,
;NLRPI - REPEAT COUNT INCREMENT ROUTINE
;IF THE DATA IS AN ASCII STRING, THERE IS A COUNT AND PNTR ARRAY
;ASSOCIATED WITH THAT STRING.
;IF THERE IS A REPEAT COUNT IN ADDITION, WE ONLY DECREMENT IT
;WHEN THE STRING IS EXHAUSTED, THAT IS, WHEN THE COUNT IS 0.
;NLRPI now checks for destination variable of type character.
;If YES, the pointers are reset and NLRP. is decremented,
;since the there is a one-to-one correspondence between
;input and destination variables of type character.
NLRPI: SKIPN NLSWRD ;Is there a string?
JRST DECRP ;NO. go decr repeat count
MOVEI T1,TP%CHR ;Type character
CAMN T1,VARTYP ;Is it?
JRST T1,RSTPTR ;YES. go reset pointers & return
MOVE T1,NLSIZ. ;Words used from string
ADDM T1,NLCPTR ;Update current pointer
MOVN T1,T1 ;Negative
ADDB T1,NLCWRD ;Compute words left
JUMPLE T1,RSTPTR ;String exhausted?
POPJ P, ;NO
;RSTPTR is an entry point from VARCHR to allow reset and
;decrement when a destination variable of type character
;follows one which is not, and the pointers have not yet
;been reset to the beginning of the string.
RSTPTR: MOVE T1,NLSPTR ;Pointer to beginning of string
MOVEM T1,NLCPTR ;Current pointer
MOVE T1,NLSWRD ;String count
MOVEM T1,NLCWRD ;Current count
DECRP: SOSLE NLRP. ;[3164]DECR REPEAT COUNT
POPJ P, ;[3164]Leave if positive
SETZM NLSBYT ;[3164]Reset string byte count
SETZM NLSWRD ;[3164]Reset string word count
POPJ P,
;NLFLST IS THE LIST OF FLAGS ASSOCIATED WITH THE CHARACTERS
;WHICH ARE LEGAL FOR THE FIRST CHARACTER OF A DATA STRING.
;THE SUBROUTINE NLFSRH CHECKS THE FLAGS ASSOCIATED WITH
;THE FIRST CHARACTER OF A DATA STRING AND MATCHES THEM
;AGAINST THE FLAGS IN THIS LIST. THE MATCH LOCATION PROVIDES
;AN INDEX INTO NLTYPE, WHICH PROVIDES A TYPE SPECIFICATION
;(AT LEAST A GUESS...) FOR THE DATA STRING, AND INTO
;NLSUB, WHICH PROVIDES THE SUBROUTINE ADDRESS FOR PROCESSING
;THE DATA STRING. TWO OF THE SUBROUTINES (TDBL AND LOGI) ARE
;ACTUALLY "TRIAL" SUBROUTINES - THEY TRY TO DO THE ACTION
;INDICATED BY THE CHARACTER, BUT MAY END UP DOING SOMETHING
;VERY DIFFERENT INDEED. (FOR GREATER DETAIL, SEE COMMENTS ATTACHED
;TO THOSE SUBROUTINES).
NLFLST: DIGFLG ;DIGIT
PNTFLG ;PERIOD
LOGFLG ;LOGICAL CHAR (T OR F)
SQFLAG ;SINGLE QUOTE
DQFLAG ;DOUBLE QUOTE
LPRFLG ;LEFT PAREN
0
NLTYPE: TP%DPR
TP%DPR ;INITIALLY ASSUME PERIOD IS D.P.
TP%LOG ;INITIALLY ASSUME T OR F IS LOGICAL
TP%LIT
TP%DPO
TP%CPX
NLSUB: PUSHJ P,%GRIN
PUSHJ P,TDBL
PUSHJ P,LOGI
PUSHJ P,ALPHI
PUSHJ P,OCTI
PUSHJ P,CPXI
;THIS IS THE CONVERSION TABLE LIST.
;THE ENTRY POSITION IS DETERMINED BY THE VALUE TYPE. THE LEFT HALF GIVES THE
;NEGATIVE # OF ENTRIES IN THE APPROPRIATE CONVERSION TABLE
;AND THE RIGHT HALF CONTAINS THE ADDRESS OF THE CONVERSION TABLE
CNVLST: 0 ;0 - NO TYPE
LOGCNV-LOGEND,,LOGCNV ;1 - LOGICAL
0 ;2 - INTEGER
0 ;3 -
0 ;4 - SINGLE REAL
0 ;5 -
OCTCNV-OCTEND,,OCTCNV ;6 - SINGLE OCTAL
0 ;7 - LABEL
DRCNV-DREND,,DRCNV ;10 - DOUBLE REAL
0 ;11 - DOUBLE INTEGER
OCTCNV-OCTEND,,OCTCNV ;12 - DOUBLE OCTAL
0 ;13 - EXTENDED DOUBLE REAL
CPXCNV-CPXEND,,CPXCNV ;14 - COMPLEX
0 ;15 - COBOL BYTE STRING
0 ;16 - CHARACTER
ALPCNV-ALPEND,,ALPCNV ;17 - ASCIZ
;NLCFLG IS THE TABLE OF CHARACTER FLAGS. IF A CHARACTER IS WITHIN
;THE RANGE 40-100, THE CHARACTER TESTING ROUTINE NLTST GETS
;THE FLAG ASSOCIATED WITH THAT CHARACTER BY USING THE CHARACTER AS
;AN INDEX INTO THIS TABLE.
NLCFLG: SPCFLG ;SPACE:40
0 ;!:41
DQFLAG ;":42
NSFLAG ;#:43
DOLFLG ;$:44
0 ;%:45
AMPFLG ;&:46
SQFLAG ;':47
LPRFLG ;(:50
RPRFLG ;):51
ASTFLG ;*:52
PLSFLG ;+:53
COMFLG ;COMMA:54
MINFLG ;-:55
PNTFLG ;PERIOD:56
SLHFLG ;/:57
DIGFLG ;0:60
DIGFLG ;1:61
DIGFLG ;2:62
DIGFLG ;3:63
DIGFLG ;4:64
DIGFLG ;5:65
DIGFLG ;6:66
DIGFLG ;7:67
DIGFLG ;8:70
DIGFLG ;9:71
COLFLG ;COLON:72
SEMFLG ;SEMI:73
LABFLG ;<:74
EQUFLG ;=:75
RABFLG ;>:76
0 ;?:77
ATFLAG ;@:100
;THESE ARE THE CONVERSION TABLES. FOR EACH TYPE OF VALUE
;(OCT, LOG, DR, CPX, ALP) THERE IS AN ASSOCIATED TABLE WHICH
;GIVES, FOR EACH TYPE OF VARIABLE, THE APPROPRIATE CONVERSION
;ROUTINE ADDRESS. IN EACH TABLE THE VARIABLE TYPE IS IN THE LEFT
;HALF OF THE WORD AND THE APPROPRIATE CONVERSION ROUTINE ADDRESS
;IS IN THE RIGHT HALF. -1 IN THE LEFT HALF MEANS THAT THE ADDRESS
;IN THE RIGHT HALF IS THE ONE FOR THE
;CONVERSION ROUTINE FOR ALL VARIABLE TYPES (THIS IS TRUE FOR OCTAL
;AND LOGICAL DATA, FOR WHICH THERE IS REALLY NO CONVERSION).
LOGCNV: -1,,OCTLOG
LOGEND==.
DRCNV: TP%LOG,,DRLOG
TP%INT,,DRINT
TP%SPR,,DRSR
TP%DPR,,DRDR
TP%DPX,,DRDPX
TP%CPX,,DRCPX
DREND==.
CPXCNV: TP%LOG,,CPXLOG
TP%INT,,CPXINT
TP%SPR,,CPXSR
TP%DPR,,CPXDR
TP%DPX,,CPXDPX
TP%CPX,,CPXCPX
CPXEND==.
ALPCNV: TP%LOG,,ALPLOG
TP%INT,,ALPINT
TP%SPR,,ALPSR
TP%DPR,,ALPDR
TP%DPX,,ALPDR
TP%CPX,,ALPCPX
ALPEND==.
OCTCNV: TP%LOG,,OCTLOG
TP%INT,,OCTINT
TP%SPR,,OCTSR
TP%DPR,,OCTDR
TP%DPX,,OCTDR
TP%CPX,,OCTDR
OCTEND==.
;THESE ARE THE ACTUAL DATA CONVERSION ROUTINES (BINARY TO
;BINARY FORM). NOTE THAT A "CONVERSION" NEVER DESTROYS
;THE ORIGINAL DATA OR ITS TYPE, BUT MERELY PUTS THE CONVERTED
;VALUE INTO NLCVL. THESE ROUTINES ASSUME THAT
;NLCVL/NLCVL.+1 HAVE BEEN INITIALIZED TO 0 AND THAT NLVAL./NLVAL.+1
;WERE INITIALIZED TO 0 BEFORE DATA WAS READ, SO THAT SINGLE
;PRECISION DATA (LOGIC) WILL YIELD 0 IN NLVAL.+1.
OCTDR:
OCTLOG:
OCTINT:
OCTSR: DMOVE T1,NLVAL. ;TRANSFER BOTH WORDS
DMOVEM T1,NLCVL. ;IT CAN'T HURT
POPJ P,
CPXDR: DMOVE T1,NLRFR ;GET REAL RAW FRACTION
DMOVEM T1,%FLRFR ;SAVE IT
MOVE T1,NLRBX ;GET REAL PART RAW EXPONENT
MOVEM T1,%FLRBX ;SAVE IT
XMOVEI T1,NLCVL. ;POINT TO CONVERTED VALUE
MOVEM T1,IO.ADR
PJRST %FLDPR ;CONVERT IT
DRDR: XMOVEI T1,NLCVL. ;POINT TO CONVERTED VALUE
MOVEM T1,IO.ADR
PJRST %FLDPR ;CONVERT IT
CPXLOG:
CPXSR: DMOVE T1,NLRFR ;GET REAL PART RAW FRACTION
DMOVEM T1,%FLRFR ;SAVE FOR CONVERT
MOVE T1,NLRBX ;GET REAL PART RAW EXPONENT
MOVEM T1,%FLRBX ;SAVE FOR CONVERT
MOVE T1,NLSGN1 ;GET REAL PART SIGN
MOVEM T1,%FLFSG ;SAVE IT
XMOVEI T1,NLCVL. ;POINT TO CONVERTED VALUE
MOVEM T1,IO.ADR ;SAVE IT
PJRST %FLSPR ;GO CONVERT IT
DRLOG:
DRCPX:
DRSR:
XMOVEI T1,NLCVL. ;POINT TO CONVERTED VALUE
MOVEM T1,IO.ADR
PJRST %FLSPR ;CONVERT TO SINGLE PRECISION
CPXINT: DMOVE T2,NLRFR ;GET SAVED RAW FRACTION
MOVE T4,NLRBX ;AND BINARY EXPONENT
MOVE T1,NLSGN1 ;GET SIGN OF REAL PART
MOVEM T1,%FLFSG ;SAVE IT
JRST XINT ;JOIN DRINT CODE
DRINT:
DMOVE T2,%FLRFR ;GET LEFT-JUSTIFIED FRACTION
MOVE T4,%FLRBX ;GET BINARY EXPONENT
JUMPLE T4,NOINT ;ZERO IF EXP .LE. 0
XINT: SETZ T1, ;CLEAR INTEGER
TLNN T3,(1B1) ;HI BIT IN LOW WORD ON?
JRST NORND ;NO
CAME T2,[377777,,777777] ;ABOUT TO OVERFLOW?
AOJA T2,NORND ;NO, ROUND UP
MOVSI T2,200000 ;YES. LOAD A HIGH BIT
ADDI T4,1 ;AND INCR BINARY EXPONENT
NORND: CAILE T4,^D35 ;WILL WE SHIFT TO OBLIVION?
JRST INTOVL ;YES. RETURN OVERFLOW
LSHC T1,1(T4) ;SHIFT INTO INTEGER
SKIPGE %FLFSG ;LOCAL MINUS?
MOVN T1,T1 ;YES. NEGATE IT
MOVEM T1,NLCVL. ;STORE IT
NOINT: POPJ P,
INTOVL: HRLOI T1,377777 ;RETURN LARGEST NUMBER
SKIPGE %FLFSG ;LOCAL MINUS?
MOVN T1,T1 ;YES. NEGATE IT
MOVEM T1,NLCVL.
$ECALL IOV ;%integer overflow
POPJ P,
CPXCPX: DMOVE T1,NLRFR ;GET REAL PART RAW FRACTION
DMOVEM T1,%FLRFR ;SAVE FOR CONVERT
MOVE T1,NLRBX ;GET RAW FRACTION
MOVEM T1,%FLRBX ;SAV FOR CONVERT
MOVE T1,NLSGN1 ;GET REAL PART LOCAL SIGN
MOVEM T1,%FLFSG ;SAVE FOR CONVERT
XMOVEI T1,NLCVL. ;POINT TO REAL PART OF CONVERTED VALUE
MOVEM T1,IO.ADR
PUSHJ P,%FLSPR ;CONVERT TO SINGLE PRECISION
DMOVE T1,NLRFR2 ;NOW THE SAME FOR IMAGINARY PART
DMOVEM T1,%FLRFR
MOVE T1,NLRBX2
MOVEM T1,%FLRBX
MOVE T1,NLSGN2
MOVEM T1,%FLFSG
XMOVEI T1,NLCVL.+1 ;POINT TO IMAG PART OF CONVERTED VALUE
MOVEM T1,IO.ADR
PJRST %FLSPR ;CONVERT TO SINGLE PRECISION
ALPINT:
ALPLOG:
ALPSR: MOVE T1,NLCPTR ;Get address of word
MOVE T1,(T1) ;Get the word
MOVEM T1,NLCVL. ;Store it
POPJ P,
CPXDPX: DMOVE T1,NLRFR ;GET REAL PART RAW FRACTION
MOVEM T1,%FLRFR ;SAVE FOR CONVERT
MOVE T1,NLRBX ;SAME FOR RAW EXPONENT
MOVEM T1,%FLRBX
MOVE T1,NLSGN1 ;GET REAL PART LOCAL SIGN
MOVEM T1,%FLFSG ;SAVE FOR CONVERT
DRDPX: XMOVEI T1,NLCVL. ;POINT TO CONVERTED VALUE
MOVEM T1,IO.ADR ;SAVE FOR CONVERSION ROUTINE
PJRST %FLGPR ;GO CONVERT IT TO G-FLOATING
ALPDR:
ALPCPX:
MOVE T1,NLCPTR ;Get address of value
DMOVE T1,(T1) ;Get 2 words
DMOVEM T1,NLCVL. ;Save them
POPJ P,
BADCNV: ;IOERR (CCC,799,519,?,Can't convert constant to correct type,,%ABORT)
$ECALL CCC,%ABORT
;NAMELIST/LDIO has its own alphameric input routine because
;we need to have the entire string available when the repeat
;count is greater than one. We input one byte at a time,
;checking only for single quotation marks ('). The first
;quotation mark denotes the beginning of the string, and
;has already been found; we skip it here. All ASCII
;characters are permissible. Two single quotation marks ('')
;in the input stream signify one input quote ('). The input
;stream is searched until only one single quote is found
;(<CRLF>) is legal within a character string. Null strings
;are illegal. If there is not room in the string buffer for
;the current byte, NLXIRB is called to double the string buffer,
;and the byte is then deposited in the new buffer. NLXIRB
;returns: T1=pointer to beginning of new buffer
; T2=pointer to byte last-deposited in new buffer
; T3=free bytes remaining in new buffer.
;When the string is complete, it is padded with from five
;to nine spaces in order to allow a MOVE-MOVEM or DMOVE-DMOVEM
;combination to fill a single or double precision variable from
;the end of the string. These spaces are not included in the
;string byte length (NLSBYT) or word length (NLSWRD).
ALPHI:
SETZM NLSBYT ;Reset byte count
PUSHJ P,SKPCHR ;Skip the initial quote
MOVE P2,NLBFLN ;Buffer-length equals bytes left
ALPLP1: PUSHJ P,GTCHRL ;Get a character
CAIE T1,"'" ;Another quote?
JRST ALPDPB ;NO. OK to deposit byte
PUSHJ P,GETCHR ;Get next character, don't call %IREC
CAIE T1,"'" ;2 quotes in a row?
JRST ALPFIN ;NO, string is complete
ALPDPB: SOJGE P2,ADPBOK ;If bytes left, OK to deposit byte
PUSH P,T1 ;Buffer empty, save character
SETZ T3, ;No minimum size
PUSHJ P,NLXIRB ;Expand buffer
MOVEI P2,(T3) ;Bytes left
POP P,T1 ;Restore character
JRST ALPDPB ;Go count this byte
ADPBOK: IDPB T1,NLCPTR ;Deposit the character in string
JRST ALPLP1 ;Loop for more
ALPFIN: MOVE T1,NLBFLN ;Buffer byte length
SUB T1,P2 ;Minus bytes remaining=string length
SKIPN T1 ;Null string?
$ECALL NLS,%ABORT ;YES. "Null string illegal"
MOVEM T1,NLSBYT ;save string length in bytes
IDIV T1,BPW(D) ;Get remainder in T2
MOVEM T1,NLSWRD ;Save string length in words
JUMPE T2,FILWRD ;If end on boundary, go space next word
AOS NLSWRD ;Remainder means partial word
SUB T2,BPW(D) ;Negative # of spaces (partial word)
FILWRD: SUB T2,BPW(D) ;Fill (another) word full of spaces
ADD P2,T2 ;Is there enough room in buffer?
JUMPGE P2,PUTSPC ;YES. Go do it
PUSH P,T2 ;Save negative count
MOVN T3,T2 ;Minimum expansion count
PUSHJ P,NLXIRB ;Expand buffer
POP P,T2 ;Restore negative count
PUTSPC: MOVEI T1," " ;Pad with spaces
DPBSPC: IDPB T1,NLCPTR ;Deposit the space
AOJL T2,DPBSPC ;Loop if more spaces
MOVE T1,NLSPTR ;Get beginning-of-buffer pointer
MOVEM T1,NLCPTR ;Set current pointer
MOVE T1,NLSWRD ;Words in string
MOVEM T1,NLCWRD ;Set current words (left)=string length
POPJ P,
;NLXIRB: Routine to expand the NAMELIST input string buffer.
;
; Doubles old buffer length, adds value in T3, rounds up to
; word boundary, and calls %MVBLK to create new buffer and
; move old buffer to beginning of new buffer. Computes the
; pointer to the last used byte in the new buffer by using
; the pointer from the old buffer and the difference between
; the pointers to the beginnings of the old and new buffers.
;
; If there is no old buffer, adds value in T3 to NLBFLN,
; rounds to word boundary, and calls %GTBLK to create the
; desired buffer.
;RETURN: T1 = pointer to beginning of (new) buffer
; T2 = pointer to last used byte in (new) buffer
; T3 = free bytes in (new) buffer
; NLBFLN, NLSPTR, & NLCPTR are updated to reflect new values.
NLXIRB: MOVE T2,NLBFLN ;Old buffer length in bytes
HRRZ T1,NLSPTR ;Old buffer address
PUSHJ P,XPNLBF ;Expand and move
HRRZ T2,NLSPTR ;Address of old buffer
MOVEM T1,NLSPTR ;Pointer to start of new buffer
HRRZI T1,(T1) ;Strip pointer stuff
SUBI T2,(T1) ;Difference between old & new addresses
MOVN T2,T2 ;Negative difference between addresses
ADDM T2,NLCPTR ;Pointer to current (first free) byte
MOVE T4,NLBFLN ;Old byte size
MOVEM T3,NLBFLN ;Store new byte size
SUBI T3,(T4) ;Return free bytes in T3
POPJ P,
XPNLBF: JUMPE T1,GTNLBF ;If none yet, go get one
MOVEI T4,(T2) ;Byte size of current buffer
LSH T4,1 ;Doubled
ADDI T4,(T3) ;(Current buffer*2)+mininum size
IDIV T2,BPW(D) ;Buffer size in words
MOVEI T3,(T4) ;Desired buffer length
ADDI T3,4 ;Round to word boundary
IDIV T3,BPW(D) ;New size in words
PUSHJ P,%MVBLK ;Expand buffer
IMUL T3,BPW(D) ;New size in bytes
HRLI T1,(POINT 7) ;Pointer to beginning of buffer
HRLI T2,(POINT 7) ;Pointer to first free byte
POPJ P, ;RETURN
GTNLBF: ADDI T3,NLDIBF+4 ;Round (initial byte size + minimum)to boundary
IDIV T3,BPW(D) ;Word size
MOVEI T1,(T3) ;Move where needed by %GTBLK
IMUL T3,BPW(D) ;Bytes that will be in buffer
PUSH P,T3 ;Destroyed by %GTBLK
PUSHJ P,%GTBLK ;Create buffer
POP P,T3 ;Restore buffer length in bytes
HRLI T1,(POINT 7) ;Pointer to beginning of buffer
MOVE T2,T1 ;Current pointer=beginning pointer
POPJ P,
;SINCE THERE IS OFFICIALLY NO DIRECT WAY TO READ COMPLEX DATA,
;IT HAS TO BE INVENTED HERE. COMPLEX DATA FOR LIST-DIRECTED I/O
;AND NAMELIST I/O IS DEFINED AS A PARENTHESIZED EXPRESSION
;CONTAINING 2 REAL CONSTANTS, DELIMITED BY A SINGLE COMMA.
CPXI: PUSHJ P,SKPCHR ;THROW AWAY "("
PUSHJ P,GETCHR ;GET NEXT CHAR, don't bump record
TXNE P1,DQFLAG ;DOUBLE QUOTE?
JRST OCTONE ;YES. GET OCTAL REAL PART
PUSHJ P,%IBACK ;THE CHAR BELONGS TO NUMBER
PUSHJ P,%GRIN ;GET ONE REAL NUMBER
JRST CPXI1
OCTONE: PUSHJ P,OCPXI ;GET OCTAL NUMBER
CPXI1: DMOVE T1,%FLRFR ;SAVE RAW FRACTION
MOVEM T1,NLRFR
MOVE T1,%FLRBX ;AND RAW BINARY EXPONENT
MOVEM T1,NLRBX
MOVE T1,%FLFSG ;GET LOCAL SIGN
XOR T1,NLSGN. ;COMBINE WITH GLOBAL SIGN
MOVEM T1,NLSGN1 ;SAVE IT
PUSHJ P,NLSDEL ;SCAN FOR DELIM
CAIE T1,"," ;WAS IT A COMMA?
$ECALL ILC,%ABORT ;"ILLEGAL CHARACTER IN DATA"
SETOM NLFV. ;SET TO IGNORE THE COMMA
XMOVEI T1,NLVL2. ;GET 2ND DEPOSIT ADDR
MOVEM T1,IO.ADR ;SAVE IT
PUSHJ P,NLNB ;SCAN FOR NEXT DELIM
TXNE P1,DQFLAG ;WAS DELIM DOUBLE QUOTE?
JRST OCTTWO ;YES. GET OCTAL IMAG PART
PUSHJ P,%IBACK ;NO. BACK UP PNTR FOR GRIN
PUSHJ P,%GRIN ;GET 2ND REAL #
JRST CPXI2
OCTTWO: PUSHJ P,OCPXI ;GET OCTAL NUMBER
CPXI2: PUSHJ P,NLSDEL ;GET 2ND DELIM
CAIE T1,")" ;MUST BE A RIGHT PAREN
$ECALL ILC,%ABORT ;"ILLEGAL CHARACTER IN DATA"
PUSHJ P,GETCHR ;THROW AWAY ")", do not get next record
DMOVE T1,%FLRFR ;SAVE AWAY THE RAW COMPONENTS
DMOVEM T1,NLRFR2 ;LOCALLY
MOVE T1,%FLRBX
MOVEM T1,NLRBX2
MOVE T1,%FLFSG ;GET LOCAL SIGN
XOR T1,NLSGN. ;COMBINE WITH GLOBAL ONE
MOVEM T1,NLSGN2 ;FOR THE IMAGINARY PART
SETZM NLSGN. ;NO GLOBAL SIGN ANYMORE
;MUST DO THIS TO PREVENT DMOVN
;OF COMPLEX VALUE, WHICH WOULD
;YIELD TRASH
POPJ P,
OCPXI: PUSHJ P,%OCTI ;GET OCTAL NUMBER
SETZM %FLFSG ;ASSUME LOCAL POSITIVE VALUE
DMOVE T1,@IO.ADR ;GET VALUE
JUMPGE T1,CPXNN ;NEGATE IF NEGATIVE
DMOVN T1,T1
SETOM %FLFSG ;GIVE LOCAL SIGN NEGATIVE
CPXNN: LDB T3,[POINT 9,T1,8] ;GET BINARY EXPONENT
MOVEM T3,%FLRBX ;SAVE AS RAW VALUE
TLZ T1,777000 ;WIPE OUT EXPONENT
ASHC T1,8 ;LEFT-JUSTIFY FRACTION
DMOVEM T1,%FLRFR ;SAVE AS RAW FRACTION
POPJ P,
;LOGI - LOCAL LOGIC INPUT ROUTINE.
;FOR NAMELIST INPUT, IF THE FIRST CHARACTER OF DATA IS A "T"
;OR "F", WE CANNOT BE SURE IF IT IS DATA OR THE
;NAME OF A NEW VARIABLE OR ARRAY TO FILL. SO WE CALL THE LOGIC
;SCANNER AND GET THE DELIMITER FOUND. IF THE DELIMITER IS
;A "=" OR "(" (WHICH ARE CONSIDERED DELIMITERS ONLY FOR NAMELIST,
;NOT FOR LIST-DIRECTED INPUT, IN THE LOGIC SCANNER), WE CALL
;SETNUL, WHICH CHECKS IF SUCH A SITUATION IS LEGAL AND SETS THE
;REST OF THE DATA DESIRED IN THE CURRENT ARRAY TO NULL ITEMS.
;THEN WE STORE THE 1ST SIX CHARACTERS FOUND BY THE LOGIC SCANNER
;FOR USE AS THE NEXT VARIABLE NAME IN THE NAMELIST.
LOGI: PUSHJ P,%LINT ;GET LOGICAL DATA
MOVE T0,FLAGS(D)
TXNE T0,D%LSD ;LIST-DIRECTED INPUT?
POPJ P, ;NO. DON'T SCAN FOR DELIM
PUSHJ P,NLSDEL ;GET THE DELIM
CAIE T1,"(" ;LEFT PAREN OR
CAIN T1,"=" ;EQUAL SIGN?
JRST NOTLOG ;OOPS - IT WAS A NEW VARIABLE
POPJ P, ;NO. IT REALLY WAS LOGIC
NOTLOG: PUSHJ P,SETNL1 ;SET REST OF DATA NULL
MOVE T1,IO.INF ;GET DATA ACCUMULATED
MOVEM T1,NLNAM. ;USE FOR NEW VARIABLE NAME
POPJ P,
;OCTAL INPUT HAS TO THROW AWAY THE INITIAL DOUBLE QUOTE BEFORE
;CALLING THE STANDARD %OCTI ROUTINE
OCTI: PUSHJ P,SKPCHR ;SKIP THE QUOTE
PJRST %OCTI ;AND GO TO STANDARD ROUTINE
;TDBL - TEST FOR DOUBLE REAL - THIS IS CALLED WHEN WE ENCOUNTER
;A PERIOD AS THE FIRST CHARACTER IN THE DATA. SINCE THE DATA
;FOLLOWING CAN BE EITHER REAL (WE ASSUME DOUBLE REAL) OR LOGIC
;(.TRUE., ETC.), WE TRY CALLING %GRIN. IF THE INFORMATION WORD
;REVEALS THAT THERE WERE NO DIGITS AFTER THE PERIOD (IT WILL STOP
;ON THE NEXT CHARACTER IF IT IS NOT A DIGIT), WE MUST ASSUME THAT
;IT IS LOGIC DATA INSTEAD. THEREFORE WE SET THE DATA TYPE TO LOGIC
;AND CALL THE LOGIC INPUT ROUTINE, WHICH WILL BARF APPROPRIATELY
;IF GARBAGE IS FOUND.
TDBL: PUSHJ P,%GRIN ;GET A REAL NUMBER
HRRZ T1,IO.INF ;ANY DIGITS AFTER DOT?
JUMPG T1,%POPJ ;OK IF YES
DSETZM NLVAL. ;NO. RESET VALUE REG
PUSHJ P,%IBACK ;MOVE PNTR TO AFTER DOT
MOVEI T1,TP%LOG ;AND ASSUME IT'S LOGICAL
MOVEM T1,VALTYP
PJRST %LINT
;NAMELIST OUTPUT - OUTPUTS ALL VARIABLES AND ARRAYS IN THE
;NAMELIST IN THE ORDER IN WHICH THEY APPEAR IN THE NAMELIST.
;BOTH VARIABLES AND NAMELIST NAMES ARE DELIMITED WITH
;COMMAS. THERE IS NO TRAILING COMMA!
%NLO: PUSHJ P,NLINIT ;INITIALIZE STUFF
MOVX T0,D%IO+D%NML ;SET FOR NMLST OUTPUT
IORM T0,FLAGS(D)
MOVEI T1,1 ;SET FOR 1PG OUTPUT
MOVEM T1,SCL.SV
PUSHJ P,CHKEND ;MAKE SURE COL 1
PUSHJ P,SPCOUT ;ADVANCE TO COL 2
MOVEI T1,"$" ;OUTPUT $
PUSHJ P,PUTCHR
MOVE T1,NLARG. ;GET NMLST ADDR
MOVEM T1,NLVAR. ;SAVE IT
MOVE T1,(T1) ;GET NAMELIST NAME
MOVEM T1,NLNAM. ;SAVE FOR OUTPUT
PUSHJ P,NLONAM ;OUTPUT IT
PUSHJ P,%ORECS ;EOL
MOVEI T1,1 ;ADD 1 TO NMLST ADDR
ADDM T1,NLVAR. ;TO GET 1ST VARIABLE PNTR
NLOLP: SKIPE T1,@NLVAR. ;ANY MORE VARS?
CAMN T1,FINCOD ;OR END CODE?
JRST NLOEND ;END OF LIST
PUSHJ P,VARSET ;SETUP VARIABLE PARAMS
MOVEI T1,^D8 ;MAKE ROOM FOR NAME AND "="
MOVEM T1,OSIZE
PUSHJ P,PUTCOM ;OUTPUT COMMA, CHECK LINE
PUSHJ P,NLONAM ;OUTPUT VARIABLE NAME
MOVEI T1,"=" ;OUTPUT =
PUSHJ P,PUTCHR
SETZM NLFLG. ;AVOID COMMA BEFORE 1ST DATA
PUSHJ P,NLMO ;MAIN OUTPUT ROUTINE
SETOM NLFLG. ;SET FLAG FOR OUTPUT STARTED
MOVEI T1,2 ;ASSUME SCALAR
ADDB T1,NLVAR. ;FOR INCR TO NEXT VARIABLE
MOVE T2,NLDIM. ;GET # DIMS
JUMPE T2,NLOLP ;CORRECT IF SCALAR
SKIPGE -1(T1) ;Array size/offset in halfwords?
AOJ T1, ;NO. One extra word
ADDI T1,1(T2) ;ADD # DIMS +1 IF ARRAY
MOVEM T1,NLVAR. ;Set to next variable
JRST NLOLP ;BACK FOR MORE
NLOEND: PUSHJ P,CHKEND ;EOL
PUSHJ P,SPCOUT ;OUTPUT SPACE
MOVEI T1,"$" ;OUTPUT $
PUSHJ P,PUTCHR
MOVEI T1,"E" ;OUTPUT E
PUSHJ P,PUTCHR
MOVEI T1,"N" ;OUTPUT N
PUSHJ P,PUTCHR
MOVEI T1,"D" ;OUTPUT D
PUSHJ P,PUTCHR
PUSHJ P,%ORECS ;EOL AGAIN
JRST %SETAV ;Reset & return
FINCOD: 4000,,0 ;NAMELIST END CODE
;FOR F10 VERSION 2 AND UP
;NLMO - NAMELIST AND LIST-DIRECTED MAIN OUTPUT ROUTINE.
;OUTPUTS A VARIABLE BY ITS TYPE; CHECKS FOR A REPEATED VALUE;
;IF THE REPEAT COUNT IS 1 IT IS NOT PRINTED. IF THE REMAINING
;NLNUM. IS NON-ZERO, A COMMA IS PRINTED AND THE PROCESS IS
;REPEATED.
NLMO: SKIPN NLNUM. ;MAKE SURE THERE'S DATA
POPJ P, ;LEAVE IF NONE
SETOM %FTSLB ;SUPPRESS LEADING BLANKS ON OUTPUT
NLMOLP: MOVE T1,VARTYP ;GET VARIABLE TYPE
CAIN T1,TP%CHR ;Character?
JRST NLDCHR ;YES. Go put out a string
MOVE T1,OSIZTB(T1) ;GET SIZE OF DATA
MOVEM T1,OSIZE ;MAKE ROOM FOR IT
SKIPE CHRLST ;[3120]Last output character string?
PUSHJ P,PUTCHK ;[3120]YES. Chk fit, RET +1 if NO, +2 if YES
PUSHJ P,PUTCOM ;[3120]CHECKS CUR POS AND DATA SIZE
SETZM CHRLST ;[3120]This is not a string
PUSHJ P,NLCRP ;CHECK FOR A REPEATED VALUE
MOVE T1,NLRP. ;GET THE REPEAT COUNT
CAILE T1,1 ;IS IT 1?
PUSHJ P,NLORP ;.GT.1. OUTPUT WITH *
XMOVEI T1,NLVAL. ;POINT TO VALUE
MOVEM T1,IO.ADR ;SAVE ADDR
MOVE T1,VARTYP ;GET VARIABLE TYPE
MOVEM T1,IO.TYP ;SAVE IT
PUSHJ P,@OUTSUB(T1) ;OUTPUT THE VALUE
SETOM NLFLG. ;SET DATA OUTPUT DONE
SKIPE NLNUM. ;ANY MORE?
JRST NLMOLP ;YES. BACK FOR MORE
POPJ P, ;NO
;HOLLERITH OUTPUT - A SIDE-EFFECT OF ALLOWING EXPRESSIONS IN I/O LISTS
;IS THAT THIS CAN NOW APPEAR, WHEREAS IT COULD NOT BEFORE. WE FAKE UP
;A CHARACTER DESCRIPTOR FOR THE HOLLERITH STRING BY (YOU GUESSED IT)
;READING THE STRING TO THE END.
HOLOUT: MOVE T1,IO.ADR ;GET ADDRESS
$BLDBP T1 ;BUILD BYTE POINTER
MOVEM T1,IO.ADR ;SAVE BYTE POINTER BACK
SETZ T2, ;CLEAR COUNT
HOLP: ILDB T3,T1 ;GET A CHAR
JUMPE T3,HOLEND ;END IS A NULL CHAR
AOJA T2,HOLP ;INCR COUNT, LOOP
HOLEND: MOVEM T2,IO.SIZ ;SAVE SIZE
JRST NLDCHR ;GO DO CHARACTER OUTPUT
; NLDCHR:
; Here from NLMOLP when VARTYP is found to be 15(CHARACTER-
; STRING), bypassing repeat-count checking. Now we simply
; move the string to the output buffer via 'MOVSLJ' IN
; %OMBYT. The STANDARD mandates NO value separators
; before or after character-strings, so we reset .NLFLG
; to pretend that the next value output is the 'first'.
;
; We must move the source string with no truncation or fill,
; filling the entire record where possible. First calculate
; space left in record. If source string remaining will not
; fit into available record, move available record length to
; source count, call %OMBYT to fill the record, call %SPCEOL
; to output the record and a leading space, and loop until
; the remaining source string will fit in available record.
; Then move the source count to destination count, call
; %OMBYT and return.
NLDCHR: MOVE T0,FLAGS(D) ;Get flags
TXNE T0,D%NML ;NAMELIST?
JRST NLCHR ;YES.
LDELEM: SETOM CHRLST ;[3120]to prevent value separator after this string
SETZM NLFLG.
PUSHJ P,%ROPOS ;get buffer position in T1
SOS T1 ;minus one = bytes already used
LOAD T3,TTYW(D) ;record size
SUB T3,T1 ;bytes left in record
JUMPN T1,LDSRCE ;At start of buffer?
MOVEI T1," " ;YES. Load a space
PUSHJ P,PUTCHR ;Store at beginning of record
LDSRCE: MOVE T1,IO.ADR ;source
MOVE T5,IO.SIZ ;bytes to be put out
LDCHLP: MOVE T0,T5 ;bytes-to-go
SUB T5,T3 ;minus bytes left in record
SKIPGE T5 ;overflow?
MOVE T3,T0 ; no, destination count = source
MOVEI T0,(T3) ;source count always = destination count
MOVEM T5,IO.EXT ;T5 crunched by %OMBYT
PUSHJ P,%OMBYT ;do it
SKIPG T5,IO.EXT ;Anything left in source string?
JRST LDNUMS ; NO. go check for more strings
PUSH P,T1 ;Destroyed by SPCEOL
PUSH P,T2 ;Destroyed by SPCEOL
PUSHJ P,SPCEOL ;Put record & leading space
POP P,T2 ;Bytes left in string
POP P,T1 ;Source pointer
LOAD T3,TTYW(D) ;Record size
JRST LDCHLP ;Go around again
LDNUMS: SOSG IO.NUM ;More items in IOLST?
POPJ P, ;NO
MOVE T1,IO.INC ;Get increment
ADJBP T1,IO.ADR ;Next element address
MOVEM T1,IO.ADR ;Set the address
JRST LDELEM ;Go put it out
NLCHR:
PUSHJ P,%ROPOS ;Find out where we are (T1 points to free byte)
SOS T1 ;Bytes actually put out so far
MOVEM T1,NLBYT ;initialize byte counter
NCHRLP: SKIPN NLFLG. ;Have we put out any values yet?
JRST NLCHR1 ;NO, skip comma
MOVEI T1,","
PUSHJ P,PTNLCH ;Put out a comma
NLCHR1: MOVE T1,NLBYT ;Find out where we are
CAIN T1,1 ;Beginning of record?
JRST NLCHR2 ;YES. Don't need separator or size check
MOVE T2,NLSIZ. ;String length(assume no internal quotes)
ADDI T2,3 ;Add two quotes & separator
LOAD T3,TTYW(D) ;Maximum record size
CAILE T2,(T3) ;Can a quoted string & space possibly fit?
JRST NLSEP ;NO. don't bother
ADD T1,T2 ;
CAIG T1,(T3) ;Will it run past end of current record?
JRST NLSEP ;Hope not
PUSHJ P,%ORECS ;Output the record & leading space
SETZM NLBYT ;Reset NAMELIST byte-count
NLSEP: MOVEI T1," "
PUSHJ P,PTNLCH ;Put out a space
NLCHR2: PUSHJ P,NLCRP ;CHECK FOR A REPEATED VALUE
MOVE T1,NLRP. ;GET THE REPEAT COUNT
CAIG T1,1 ;IS IT 1?
JRST NLCHR3 ;YES
PUSHJ P,NLORP ;.GT.1. OUTPUT WITH *
PUSHJ P,%ROPOS ;Get byte position of first free byte
SOS T1 ;Convert to byte count
MOVEM T1,NLBYT ;Set current byte count
NLCHR3: MOVEI T1,"'" ;Initial quotation mark
PUSHJ P,PTNLCH ;Put it out
MOVE T5,NLSIZ. ;String length
NLCHLP: ILDB T1,NLADD. ;Load next byte
CAIE T1,"'" ;Is it a quote?
JRST NCHLP1 ; NO.
PUSHJ P,%ROPOS ;Get byte position of next free byte
LOAD T2,TTYW(D) ;Get position of last byte in record
CAIL T1,(T2) ;Is it the last byte?
PUSHJ P,SPCEOL ; YES
MOVEI T1,"'" ;Reload the quote
PUSHJ P,PTNLCH ;Put out leading quote
NCHLP1: PUSHJ P,PTNLCH ;Put out the character
SOJG T5,NLCHLP ;Loop thru string
MOVEI T1,"'" ;Load a quote
PUSHJ P,PTNLCH ;Put it out
SETOM NLFLG. ;Flag that we did it
SKIPN NLNUM. ;Any more strings?
POPJ P, ;NO.
MOVE T1,NLRP. ;Repeat count
SOS T1 ;We just put one out
IMUL T1,NLINC. ;Calculate offset to next variable
ADJBP T1,NLADD. ;Adjust to address/next variable
MOVEM T1,NLADD. ;Store address/next variable
MOVEM T1,IO.ADR ;Store for NLCSTR
JRST NCHRLP ;Loop thru IOLST
SEGMENT DATA
IO.EXT: BLOCK 1 ;
SEGMENT CODE
;NLCRP - ROUTINE TO CHECK FOR A REPEATED VALUE
;PLACES THE (SINGLE OR DOUBLE WORD) VALUE POINTED TO BY
;NLVAL. AND THEN INCREMENTS A LOCAL POINTER AND CHECKS
;THE NEXT ENTRY FOR AN IDENTICAL VALUE; THIS PROCESS IS
;CONTINUED UNTIL A NON-MATCH IS FOUND. THE ADDRESS OF THE
;NON-MATCHING ENTRY IS SAVED IN NLADD., THE NUMBER OF
;REPEATED VALUES IS PLACED IN NLRP., AND NLNUM. IS
;DECREMENTED APPROPRIATELY.
;NOTE THAT THERE IS NO WAY FOR THIS ROUTINE TO CHECK FOR
;VALUES THAT DIFFER BEYOND THE OUTPUT ACCURACY (AND THEREFORE
;PRINT THE SAME), NOR DOES THIS ROUTINE CHECK FOR IDENTICAL
;VALUES ACROSS DIFFERENT VARIABLES.
NLCRP: MOVEI T1,1 ;ASSUME REPEAT COUNT OF 1
MOVEM T1,NLRP.
MOVE T0,VARTYP ;GET VARIABLE TYPE
CAIN T0,TP%CHR ;CHARACTER?
JRST NLCSTR ;YES. GO DO BYTE STRING COMPARISONS
SETZ T2, ;CLEAR 2ND VALUE WORD
MOVE T3,NLSIZ. ;GET SIZE
XCT NLGET(T3) ;GET THE VALUE
DMOVEM T1,NLVAL. ;SAVE IT
NLCLP: MOVE T1,NLINC. ;INCR ADDR
ADDM T1,NLADD.
SOSG NLNUM. ;ANY MORE ENTRIES?
POPJ P, ;NO. LEAVE
SETZ T2, ;CLEAR 2ND VALUE WORD
XCT NLGET(T3) ;GET NEXT ENTRY
CAMN T1,NLVAL. ;COMPARE
CAME T2,NLVAL.+1
POPJ P, ;THEY DIDN'T MATCH
AOS NLRP. ;THEY DID. INCR RPT COUNT
JRST NLCLP ;AND TRY AGAIN
;NLCSTR:
; Compares strings for repeated values.
NLCSTR: SOSGE NLNUM. ;Any more elements?
POPJ P, ;NO
MOVE T1,NLINC. ;Byte size
MOVEI T3,(T1) ;Save byte size for comparison
MOVE T4,NLADD. ;Current string
ADJBP T1,IO.ADR ;Point to next element
MOVEM T1,IO.ADR ;Store the pointer
MOVEI T0,(T3) ;String counts are the same
EXTEND T0,[CMPSE
" "
" "] ;Strings identical?
POPJ P, ;NO
AOS NLRP. ;Count repeated string
JRST NLCSTR ;Loop thru iolst
;NLONAM - OUTPUT A SIXBIT NAME
NLONAM: MOVE T1,[POINT 6,NLNAM.] ;GET PNTR
MOVEM T1,NLVAL. ;SAVE IT
MOVEI T1,6 ;MAX COUNT
MOVEM T1,NLRP. ;SAVE IT
NLONLP: ILDB T1,NLVAL. ;GET CHAR
JUMPE T1,NLONF ;DONE IS 0
ADDI T1,40 ;CONVERT TO ASCII
PUSHJ P,PUTCHR ;OUTPUT IT
SOSLE NLRP. ;DECR COUNT
JRST NLONLP ;BACK FOR MORE
NLONF: POPJ P,
;NLORP - OUTPUT REPEAT COUNT AND *
NLORP: XMOVEI T1,NLRP. ;GET REPEAT COUNT ADDR
MOVEM T1,IO.ADR ;SAVE IT
PUSHJ P,%GINTO ;OUTPUT IT
MOVEI T1,"*" ;OUTPUT *
PJRST PUTCHR
;PUTCHK - CHECK LINE - USED FOR DELIMITING DATA ITEMS
;AND VARIABLE NAMES IN THE OUTPUT STREAM. IF THE LINE OF OUTPUT
;IS ABOUT TO BE "TOO LONG" (DEFINED BY TTYW MINUS DATA SIZE
;FOR THE NEXT ITEM) A NEW LINE IS STARTED.
PUTCHK: PUSHJ P,%ROPOS ;GET CURRENT POSITION
ADD T1,OSIZE ;ALLOW ROOM FOR VALUE
LOAD T2,TTYW(D) ;GET WIDTH
CAIG T1,(T2) ;WOULD IT OVERFLOW WIDTH?
AOS (P) ;NO. SKIP RETURN
POPJ P,
;PUTCOM - OUTPUT COMMA IF PREV OUTPUT, CHECK FOR LINE-TOO-LONG, AND
;OUTPUT SPACE.
PUTCOM: MOVEI T1,"," ;OUTPUT COMMA
SKIPE NLFLG. ;ONLY IF PREVIOUS DATA
PUSHJ P,PUTCHR
PUSHJ P,PUTCHK ;WILL WE OVERFLOW LINE?
SPCEOL: PUSHJ P,%ORECS ;YES. OUTPUT EOL
SPCOUT: MOVEI T1," " ;PLUS A SPACE
PJRST PUTCHR
;CHKEND - TO MAKE SURE THAT WE ARE AT THE BEGINNING OF THE LINE
;WHEN WE OUTPUT THE NAMELIST "BEGIN STRING" - A SPACE
;AND DOLLAR SIGN.
;PUTEND - FORCES OUTPUT OF LAST RECORD AND STARTS NEW LINE
CHKEND: PUSHJ P,%ROPOS ;GET CURRENT POSITION
CAIN T1,1 ;NEW LINE?
POPJ P, ; YES, QUIT
PJRST %ORECS ;NO, FORCE EOL
;WE HAVE FUNNELED ALL OUTPUT CHARACTER CALLS THROUGH HERE, SO THAT IF SOMEDAY
;SOMEONE WANTS SOMETHING SPECIAL DONE WHICH IS NOT PART OF %OBYTE, IT CAN BE
;DONE HERE AND BE GLOBAL FOR ALL OF NAMELIST OUTPUT.
SEGMENT DATA
NLBYT: BLOCK 1
SEGMENT CODE
PTNLCH: AOS NLBYT ;Count this byte
LOAD T2,TTYW(D) ;Record size
CAML T2,NLBYT ;Will we overflow the line?
JRST PUTCHR ;NO
PUSH P,T1 ;Save the character
PUSHJ P,SPCEOL ;Output record & a leading space
MOVEI T1,1 ;Count the space
MOVEM T1,NLBYT ;Reset output count
POP P,T1 ;Get the character
JRST PTNLCH ;It better go out this time!!!
PUTCHR==%OBYTE
;THIS IS THE TABLE OF "OUTPUT SUBROUTINES BY TYPE". THE VARIABLE
;TYPE IS USED AS THE INDEX INTO THE TABLE.
OUTSUB: IFIW %GINTO ;0 NOT SPECIFIED
IFIW %LOUT ;1 LOGICAL
IFIW %GINTO ;2 INTEGER
IFIW NONO ;3
IFIW %GROUT ;4 SINGLE REAL
IFIW NONO ;5
IFIW %OCTO ;6 SINGLE OCTAL
IFIW NONO ;7 STATEMENT LABEL
IFIW %GROUT ;10 DOUBLE REAL
IFIW NONO ;11 DOUBLE INTEGER
IFIW %OCTO ;12 DOUBLE OCTAL
IFIW %GROUT ;13 EE DOUBLE REAL
IFIW CPXO ;14 COMPLEX
IFIW NONO ;15 COBOL BYTE STRING
IFIW NONO ;16
IFIW HOLOUT ;17 ASCIZ
NLGET: JFCL
MOVE T1,@NLADD.
DMOVE T1,@NLADD.
;OUTPUT DATA ELEMENT SIZE TABLE - GIVES MAXIMUM SIZE OF A DATA ELEMENT
;BASED ON ITS DATA TYPE
OSIZTB: ^D14 ;0 (BADLY SPECIFIED INTEGER)
3 ;1 LOGICAL
^D14 ;2 INTEGER
0 ;3
^D16 ;4 REAL
0 ;5
0 ;6
0 ;7
^D16 ;10 DOUBLE REAL
0 ;11
0 ;12
^D16 ;13 EE DOUBLE REAL
^D32 ;14 COMPLEX
0 ;15
0 ;16
0 ;17
;CPXO - SIMILAR TO CPXI - SINCE THERE IS NO OFFICIAL ROUTINE
;FOR COMPLEX VARIABLE OUTPUT, WE HAVE TO DO IT HERE, SENDING
;EACH PART OUT THROUGH %GROUT (WHICH MUST BE FOOLED INTO
;THINKING THE VARIABLE TYPE IS SINGLE REAL...).
CPXO: MOVEI T1,TP%SPR ;MAKE THE TYPE SINGLE REAL
MOVEM T1,IO.TYP
MOVEI T1,"(" ;OUTPUT LEFT PAREN
PUSHJ P,PUTCHR
PUSHJ P,%GROUT ;OUTPUT REAL PART
MOVEI T1,TP%SPR ;USE REAL DATA SIZE
MOVE T1,OSIZTB(T1) ;FROM SIZE TABLE
MOVEM T1,OSIZE ;TO CHECK FOR ENOUGH ROOM
MOVEI T1,"," ;OUTPUT COMMA
PUSHJ P,PUTCHR
PUSHJ P,PUTCHK ;AND CHECK FOR LINE-TOO-LONG
PUSHJ P,SPCEOL ;IN WHICH CASE OUTPUT EOL
XMOVEI T1,NLVAL.+1 ;OUTPUT IMAGINARY PART
MOVEM T1,IO.ADR ;SAVE FOR OUTPUT
PUSHJ P,%GROUT
MOVEI T1,")" ;OUTPUT RIGHT PAREN
PJRST PUTCHR
NONO: $SNH ;NONEXISTENT OUTPUT ROUTINE
PURGE $SEG$
END