Trailing-Edge
-
PDP-10 Archives
-
BB-D480C-SB_1981
-
forfmt.mac
There are 11 other files named forfmt.mac in the archive. Click here to see a list.
SEARCH FORPRM
TV FORFMT FORMAT PROCESSOR,6(2033)
;COPYRIGHT (C) 1981 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
;TRANSFERRED.
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
;AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
COMMENT \
***** Begin Revision History *****
1100 JLC New
1164 CKS 27-Oct-80
Prevent TL from going off left end of record
1207 JLC 19-Dec-80
Prevent %%GETIO from substituting REAL for COMPLEX for
list-directed I/O
1215 JLC 6-Jan-81
SFDEL was dropping off the end into dollar format. Inserted a
POPJ. Edit revhist actually inserted 9-Feb-81, was lost.
1230 JLC 20-Jan-81
Increased size of repeat count to 9 bits, decreased size of
exponent field to 3 bits.
1306 DAW 26-Feb-81
New arg list format from %SAVE
1321 DAW 6-Mar-81
More changes for extended addressing support.
1324 EDS 9-Mar-81 Q20-01396
Add an encoding address for DOLLAR ($) and COLON (:) format
so that ($10A5) is not treated as ($10,A5). These should
use the same encoding as SLASH (/) format.
1334 DAW 12-Mar-81
Use new macros $BLDBP, $LODBP, $STRBP to clean up the code.
1416 JLC 10-Apr-81
Q format must use IRBUF.
1464 DAW 12-May-81
Error messages.
1467 CKS 18-May-81
Change EXTADD to I.EXT, change TITLE to FORFMT to correspond to
file name
1473 CKS 21-May-81
Error message fixes.
1521 JLC 26-Jun-81
Fix formatted EOF processing: in input loop, check if pending
EOF. If so, toss rest of I/O list.
1532 DAW 14-Jul-81
OPEN rewrite: Base level 1
1535 JLC 14-Jul-81
Remove EOF handling from here, now handled in %DOIO.
1552 DMN 21-Jul-81
Performance enhancements.
1562 DMN 28-Jul-81
Performance enhancements.
1566 JLC 29-Jul-81
Add error diagnostics for digits with no formats, any repeat
count for $,/,Q, etc.
1575 JLC 05-Aug-81
Edit 1566 was too all-inclusive, made repeat count of left
paren break. Fix by making left paren not a delimiter,
then check in left paren routine for previous format.
1600 DAW 11-Aug-81
Allow "X" to mean "1X" (as it used to!)
1605 JLC 12-Aug-81
Fix ambiguous (A419X) to be error. Fix T to be a delimiter.
1615 DAW 19-Aug-81
Get rid of two word BP option.
1622 JLC 21-Aug-81
Fix Q format encoding, was accumulating digits after it.
Fix no-comma syntax, compile prev format if leftover
format char.
1625 DAW 21-Aug-81
Get rid of "DF".
1705 JLC 11-Sep-81
Fixed serious T-format bug. Now send %SPOS position desired
for next character (minimum 1) so that ORVIR in %OBYTE will
never have zero for a positioning command.
1730 JLC 18-Sep-81
Another bug fix for T-format. Sped up format encoding by
eliminating FMTSS and using a local stack instead.
1775 JLC 9-Oct-81
Fix X format. Was being truncated to 8 bits.
2033 JLC 15-Nov-81
Make "Data in IO list but not in format" go to %ABORT.
Fix A free format.
***** End Revision History *****
\
ENTRY %FORMT
EXTERN %OBYTE,%GETIO,%IBYTE,%IBYTC,%IREC,%ORECS,%RPOS,%SPOS
EXTERN %ALPHI,%ALPHO,%DIRT,%DOUBT,%ERIN,%EOUT,%FLIRT,%FLOUT
EXTERN %LINT,%LOUT,%GRIN,%GROUT,%INTI,%INTO,%RIGHI,%RIGHO
EXTERN %GLINT,%GLOUT,%GINTI,%GINTO,%GOCTI,%GOCTO
EXTERN %OCTI,%OCTO,%HEXI,%HEXO,%SIZTB
EXTERN %GTBLK,%FREBL,%SAVE4,%IBACK,%OVNUM
EXTERN %ABORT,%POPJ,%POPJ1
EXTERN FMT.LS
EXTERN A.FMT,T.FMT,A.FMS
EXTERN I.EXT
INTERN %FMTSV,%FMTCL
INTERN SCL.SV,USR.AD,USR.TY,USR.SZ,ENC.WD
INTERN W.PNTR,D.PNTR,X.PNTR
INTERN FMT.BG,FMT.BP,FMT.SZ
;ENCODED FORMAT BLOCK PARAMS
%FMTNX==0 ;NEXT ENCODED FORMAT ADDR
%FMTAD==1 ;ACTUAL ADDR OF FORMAT STATEMENT
%FMTRP==2 ;INDEFINITE REPEAT PNTR
%FMTEN==3 ;FIRST WORD OF ENCODED FORMAT
TP%LBL==7
DATFLG==1,,0 ;DATA READ OR WRITTEN
FDFLG==2,,0 ;FORMAT DELIMITER
REGFLG==4,,0 ;REGISTER FORMAT CHARACTER
IGNFLG==10,,0 ;IGNORE CHARACTER
IOLFLG==20,,0 ;I/O LIST ENTRY NEEDED
SKPFLG==40,,0 ;SKIP TO DELIM AFTER SCAN
DRFLG==FDFLG+REGFLG ;DELIMITER+REGISTER
DRIFLG==DRFLG+IOLFLG ;DELIMITER+REGISTER+I/O LIST ENTRY
DTIFLG==DATFLG+REGFLG+IOLFLG ;DATA+REGISTER+I/O LIST ENTRY
DTISFL==DTIFLG+SKPFLG ;DATA+REGISTER+I/O LIST ENTRY+CALL SFDEL
SEGMENT DATA
;DDB BLOCK VARIABLES - USED DURING EXECUTION
FMT.LK: 0 ;PNTR TO ENCODED LEFT PAREN (RH=LINK TO AFTER LOOP)
SCL.SV: 0 ;SCALE FACTOR
ENC.AD: 0 ;ADDRESS OF CURRENT ENCODED FORMAT
ENC.PT: 0 ;FORMAT STACK POINTER
ENC.RP: 0 ;LOOP EXECUTION REPEAT COUNT
ENC.LR: 0 ;LOCAL REPEAT COUNT
;LOCAL VARIABLES - USED BY THE FORMAT ENCODER AND/OR AS TEMPS
;BY THE FORMAT EXECUTION
SAV.EF: 0 ;ADDR OF LOC TO SAVE ADDR OF ENCODED FORMAT
RPT.PT: 0 ;INDEFINITE REPEAT POINTER
FMT.BG: 0 ;BYTE POINTER TO BEGINNING OF FORMAT
FMT.BP: 0 ;FORMAT BYTE POINTER
FMT.IU: 0 ;I/O LIST ENTRY USED FLAG
NUM.AD: 0 ;DIGIT ACCUMULATOR PNTR
ENC.WD: 0 ;ENCODED FORMAT WORD
USR.TY: 0 ;FORMAT ARG TYPE
USR.AD: 0 ;ACTUAL FORMAT ADDRESS
USR.SZ: 0 ;SIZE OF FORMAT IN WORDS
FMT.CC: 0 ;CURRENT FORMAT CHAR
FMT.PC: 0 ;PREVIOUS CHAR
FMT.SZ: 0 ;SIZE OF FORMAT IN CHARS
FMT.DB: ;ENCODING DATABASE - CLEARED BY FMTINT
FMT.SG: 0 ;SIGN
FMT.WD: 0 ;FORMAT WIDTH
FMT.DW: 0 ;DECIMAL WIDTH
FMT.CH: 0 ;FORMAT CHARACTER (SIXBIT)
FMT.EW: 0 ;EXPONENT WIDTH (do not split FMT.EW and FMT.RP)
FMT.RP: 0 ;REPEAT COUNT
FMT.EN==.-1 ;END OF ENCODING DATABASE
SEGMEN CODE
;BYTE POINTERS TO FORMAT ATTRIBUTES (WIDTH, DECIMAL WIDTH, ETC.)
W.PNTR:
WIDPNT: POINT 8,ENC.WD,8 ;TOTAL WIDTH OF FORMAT ELEMENT
;AVOID BIT 0 SO IT WON'T BE NEGATIVE
;AS NEGATIVE MEANS PAREN REPEAT
RPTPNT: POINT 12,ENC.WD,20 ;REPEAT COUNT
D.PNTR:
DECPNT: POINT 6,ENC.WD,26 ;DECIMAL WIDTH
X.PNTR:
EWPNT: POINT 3,ENC.WD,29 ;EXPONENT WIDTH
CODPNT: POINT 6,ENC.WD,35 ;FORMAT CODE (SIXBIT CHAR)
;THE FOLLOWING TABLE CONTAINS INFORMATION ON HOW TO TREAT
;EACH CHARACTER FOUND IN A FORMAT STATEMENT. THE
;TABLE IS ARRANGED SO THAT THE CHARACTER (TRANSLATED TO SIXBIT)
;CAN BE USED AS AN INDEX INTO THE TABLE. THE LEFT HALF OF EACH
;WORD CONTAINS THE FLAGS ASSOCIATED WITH THE CHARACTER (FOR INSTANCE,
;THE LEFT HALF OF THE ENTRY FOR 'A' HAS DTIFLG, WHICH IS A COMPOSITE
;OF FLAGS WHICH DIRECT THE FORMAT ENCODER TO REGISTER THE FORMAT,
;THAT IS, IT IS A "MAIN" FORMAT CHARACTER,
;AND THAT THIS FORMAT CHARACTER HAS AN ITEM OF DATA ASSOCIATED WITH IT).
;THE RIGHT HALF OF EACH ENTRY IS THE ADDRESS OF ANOTHER TABLE ENTRY
;WHICH CONTAINS THE ADDRESS OF ANY SPECIAL
;CODE TO EXECUTE FOR THE PROCESSING OF THE FORMAT CHARACTER.
FMT.CT: IGNFLG ;SPACE
0 ;!
0 ;"
0 ;#
DRFLG+DOLFMT ;$
0 ;%
0 ;&
DRFLG+SQFMT ;'
LPRFMT ;(
FDFLG+RPRFMT ;)
0 ;*
IGNFLG ;+
FDFLG ;COMMA
MINFMT ;-
PERFMT ;.
DRFLG+SLHFMT ;/
DIGFMT ;0
DIGFMT ;1
DIGFMT ;2
DIGFMT ;3
DIGFMT ;4
DIGFMT ;5
DIGFMT ;6
DIGFMT ;7
DIGFMT ;8
DIGFMT ;9
DRFLG+COLFMT ;:
0 ;;
0 ;<
0 ;=
0 ;>
0 ;?
0 ;@
DTIFLG+AFMT ;A
DRFLG+BFMT ;B
0 ;C
DTISFL+DFMT ;D
DTISFL+EFMT ;E
DTISFL+FFMT ;F
DTISFL+GFMT ;G
REGFLG+HFMT ;H
DTISFL+IFMT ;I
0 ;J
0 ;K
DTISFL+LFMT ;L
0 ;M
0 ;N
DTISFL+OFMT ;O
REGFLG+PFMT ;P
DRIFLG+QFMT ;Q
DTISFL+RFMT ;R
DRFLG+SFMT ;S
DRFLG+TFMT ;T
0 ;U
0 ;V
0 ;W
REGFLG+XFMT ;X
0 ;Y
DTISFL+ZFMT ;Z
0 ;[
0 ;\
0 ;]
0 ;^
0 ;_
;THERE ARE TWO STEPS INVOLVED HERE, FORMAT ENCODING AND FORMAT
;EXECUTION. FORMAT ENCODING INVOLVES CODING EACH "MAIN" FORMAT
;CHARACTER (SUCH AS A,E,I, ETC.) INTO A WORD (OR 2) CONTAINING
;THE FORMAT WIDTH, REPEAT COUNT, DECIMAL WIDTH, ETC. THIS ENCODING
;IS DONE BECAUSE STRAIGHT INTERPRETIVE EXECUTION OF FORMAT
;STATEMENTS IS SLOW AND AWKWARD (ESPECIALLY WITH INDEFINITE REPEAT).
;ONCE A FORMAT STATEMENT IS ENCODED, THE ENCODED VERSION IS SAVED
;FOR LATER USE. THERE IS SOME OVERHEAD SEARCHING FOR THE
;ENCODED VERSION, BUT THIS IS CUT DOWN BY HAVING FMTN DIFFERENT LINKED
;LISTS WHERE IT CAN RESIDE. (DIVIDING BY FMTN GIVES
;WHICH LIST TO SEARCH). FORMATS IN ARRAYS ARE ALSO ENCODED, BUT
;UNDER NORMAL CIRCUMSTANCES THE ENCODED VERSIONS ARE NOT SAVED;
;THE USER MAY FORCE FOROTS TO KEEP THEM, HOWEVER, WITH
;A SPECIAL SUBROUTINE CALL (FMTSAV).
;IN ORDER TO FACILITATE THE PROCESSING OF PARENS IN THE FORMAT
;STATEMENT, THE CODE FOR PROCESSING IS FULLY RECURSIVE. A PAREN
;IS ENCODED WITH AN ASSOCIATED COUNT AND A LINK
;TO THE ENCODED ENTRIES AFTER THE ASSOCIATED RIGHT PAREN. A
;RIGHT PAREN IS ENCODED AS A ZERO ENTRY. THIS STRUCTURE FACILITATES
;A SIMPLE RECURSIVE PROCEDURE FOR EXECUTION OF THE FORMAT
;AND ALSO FACILITATES THE PROCESSING OF INDEFINITE REPEAT. ITS
;DISADVANTAGE IS THAT THE STACK LENGTH RESTRICTS THE NUMBER
;OF IMBEDDED PARENS.
;THERE ARE SEVERAL PATHOLOGICAL CASES OF INTEREST.
;IF THE USER SPECIFIES A FORMAT IN AN ARRAY, S/HE MAY LEAVE OFF
;ONE OR BOTH PARENS. IF THE LEFT PAREN IS MISSING, AND THERE ARE
;NO LEFT PARENS IN THE REST OF THE FORMAT STATEMENT, THE ENCODER
;WILL NEVER BE CALLED RECURSIVELY; WHETHER OR NOT THE FORMAT ENDS
;WITH A RIGHT PAREN, AN "END PAREN" ENTRY (A ZERO WORD) WILL
;BE PLACED AT THE END OF THE ENCODED FORMAT, AND WILL THUS
;EXECUTE CORRECTLY. IF THERE ARE LEFT PARENS IMBEDDED IN THE FORMAT,
;THE ENCODER WILL BE CALLED CORRECTLY, RECURSIVELY. THE ENCODER
;WILL CONTINUE BEYOND THE MATCHING RIGHT PARENS UNTIL IT ENCOUNTERS
;EITHER AN UNMATCHED RIGHT PAREN OR THE END OF THE FORMAT; IN THIS CASE
;IT WILL ALSO EXECUTE CORRECTLY, AS IF THERE HAD BEEN A BEGINNING
;LEFT PAREN.
;INDEFINITE REPEAT IS HANDLED BY SAVING A POINTER TO THE LAST ENCODED
;LEFT PAREN IN THE FORMAT STATEMENT MATCHING THE
;NEXT TO LAST RIGHT PAREN (WHICH MAY BE THE INITIAL LEFT
;LEFT PAREN, OR IMPLIED LEFT PAREN IF THE USER FORGOT IT...). THUS,
;IN ACCORDANCE WITH THE ANSI-66 AND ANSI-77 STANDARDS, THE LOOP
;USED IS THE ONE PRECEDING THE FINAL RIGHT PAREN, OR THE ENTIRE
;FORMAT STATEMENT IF THERE IS NO INTERNAL LOOP.
;AN ENCODED FORMAT IS AS FOLLOWS:
;
;WORD DESCRIPTION
;
; 0 ADDR OF NEXT ENCODED FORMAT IN THIS LIST
; 1 LINK NUMBER ,, ADDR OF ACTUAL FORMAT
; 2 INDEFINITE REPEAT POINTER
; 3 ENCODED WORD 1
; 4 ENCODED WORD 2
; . .
; . .
;
;THERE ARE MANY SUCH LINKED LISTS OF ENCODED FORMATS, THE NUMBER
;DETERMINED BY THE FORPRM PARAMETER FMTN, WHICH SERVES AS A
;HASHING NUMBER - THE USER'S FORMAT ADDRESS IS DIVIDED BY THIS
;NUMBER, AND THE REMAINDER IS USED AS AN INDEX INTO THE ENCODED
;FORMAT LIST OF LISTS (FMT.LS). EACH ENTRY IN FMT.LS POINTS
;TO THE BEGINNING OF A LINKED LIST OF ENCODED FORMATS.
;
;PROVISION HAS BEEN MADE FOR THE USER TO SPECIFY THAT A FORMAT
;IN AN ARRAY SHOULD BE ENCODED AND STORED (UNDER NORMAL CIRCUMSTANCES
;THE ENCODED FORMAT FROM AN ARRAY IS THROWN AWAY). THIS FEATURE IS
;PROVIDED VIA TWO SPECIAL CALLS - FMTSAV & FMTCLR:
;
; CALL FMTSAV (array name, number of array elements)
;
; THIS CALL CALLS THE FORMAT ENCODER AND FORCES IT
; TO SAVE THE ENCODED FORMAT. IF THIS ROUTINE IS
; CALLED WITH AN ARRAY WHICH HAS ALREADY BEEN
; ENCODED, THE OLD ENCODING WILL BE THROWN AWAY
; AND A NEW ONE CREATED.
;
; CALL FMTCLR (array name)
;
; THIS CALL THROWS AWAY THE ENCODED FORMAT BY
; DEALLOCATING THE CORE AND RELINKING THE
; OTHER ENCODED FORMATS IN THE LIST.
;
;THE IMPLEMENTATION OF THESE SUBROUTINES MAKES IT NECESSARY TO
;SEARCH THE LISTS OF ENCODED FORMATS WHETHER OR NOT THE FORMAT IS
;IN AN ARRAY. HOWEVER, SINCE THE LISTS HAVE BEEN HASH-CODED, THIS
;SHOULD NOT SLOW PROCESSING SIGNIFICANTLY.
;%FORMT IS THE FORMAT CALL FROM FOROTS. WE FIRST SEARCH FOR
;THE FORMAT IN THE LIST OF ENCODED FORMATS. IF IT EXISTS,
;WE GO ON TO FORMAT EXECUTION. OTHERWISE, WE ENCODE IT AND THEN
;EXECUTE IT.
%FORMT: MOVE T1,A.FMT ;GET ADDRESS OF FORMAT
PUSHJ P,%OVNUM ;GET LINK NUMBER ALSO
MOVEM T1,USR.AD ;SAVE IT
MOVE T2,A.FMS ;GET SIZE
MOVEM T2,USR.SZ ;SAVE IT
MOVE T1,T.FMT ;GET ARG TYPE
MOVEM T1,USR.TY ;SAVE IT
PUSHJ P,FMTSRH ;SEARCH FOR ENCODED FORMAT
MOVEM T1,ENC.AD ;SAVE THE ADDR FOUND
JUMPN T1,NOENC ;GO EXECUTE IF ALREADY ENCODED
PUSHJ P,FMTENC ;ENCODE THE FORMAT
MOVE T1,USR.TY ;GET FORMAT TYPE
CAIN T1,TP%LBL ;LABEL?
JRST SAVENC ;YES. GO SAVE IT
PUSHJ P,FMTEXC ;NO. EXECUTE THE FORMAT
MOVE T1,ENC.AD ;FREE THE CORE WE GOT
PJRST %FREBL ;FREE IT UP
SAVENC: MOVE T1,ENC.AD ;GET THE ENCODED ADDR
MOVEM T1,@SAV.EF ;SAVE IT ON LINKED LIST
NOENC: PJRST FMTEXC ;EXECUTE THE FORMAT
%ADR==0 ;USER ARRAY ADDRESS
%SIZ==1 ;USER ARRAY SIZE (IN ARRAY ELEMENTS)
;THIS IS THE FAMOUS ARRAY FORMAT ENCODER. IT ALLOWS THE USER
;TO HAVE FOROTS SAVE AWAY THE ENCODED VERSION OF THE FORMAT IN AN ARRAY.
;IF IT HAS ALREADY BEEN ENCODED, THE OLD ENCODING IS THROWN AWAY
;AND THE NEW ONE IS INSERTED AT THE END OF THE APPROPRIATE LINKED
;ENCODED FORMAT LIST.
%FMTSV: MOVEI T1,@%ADR(L) ;GET ARRAY ADDR
PUSHJ P,%OVNUM ;GET LINK NUMBER ALSO
MOVEM T1,USR.AD ;SAVE IT
LDB T1,[POINTR %ADR(L),ARGTYP];GET ARRAY TYPE
MOVE T2,@%SIZ(L) ;GET # ARRAY ELEMENTS
IMUL T2,%SIZTB(T1) ;GET # WORDS
MOVEM T2,USR.SZ ;SAVE IT
PUSHJ P,FMTSRH ;SEARCH FOR THE FORMAT
JUMPE T1,GOENC ;IF NOT FOUND, GO ENCODE IT
PUSHJ P,FMTDEL ;FOUND. DELETE IT
PUSHJ P,FMTSR1 ;SEARCH AGAIN
JUMPN T1,FMTER3 ;BETTER NOT BE THERE AGAIN!
GOENC: PUSHJ P,FMTENC ;ENCODE THE FORMAT
MOVE T1,ENC.AD ;AND LINK INTO THE LIST
MOVEM T1,@SAV.EF
POPJ P,
;AND THIS IS THE FAMOUS ENCODED FORMAT DEALLOCATOR, WHICH
;IS HERE MAINLY FOR SYMMETRY (OR FOR THE USER WHO REALLY CARES
;ABOUT THE EXTRA FEW WORDS OF CORE ALLOCATED FOR THE ENCODED
;FORMAT).
%FMTCL: MOVEI T1,@%ADR(L) ;GET ARRAY ADDR
MOVEM T1,USR.AD ;SAVE FOR SEARCH
PUSHJ P,FMTSRH ;SEARCH FOR THE FORMAT
JUMPE T1,%POPJ ;NOT FOUND. JUST LEAVE
; PJRST FMTDEL ;DELETE IT
;SUBROUTINE TO DELETE AN ENCODED FORMAT FROM A LINKED LIST.
;T1 POINTS TO THE ENCODED FORMAT TO BE DELETED, SAV.EF POINTS
;TO THE PREVIOUS ENCODED FORMAT.
FMTDEL: MOVE T2,(T1) ;GET ADDR OF NEXT FORMAT
MOVEM T2,@SAV.EF ;RELINK THE LIST
PJRST %FREBL ;FREE THE ALLOCATED CORE
;THIS IS THE FORMAT ENCODER SETUP. THE SIZE OF THE CORE WE ALLOCATE
;IS DETERMINED BY THE SIZE OF THE FORMAT STATEMENT OR ARRAY, IN
;CHARACTERS. WHILE THIS IS AN INEXACT MEASURE (USUALLY MUCH MORE
;THAN NECESSARY), IT IS AT LEAST SAFE, AND WE HAVE NO BETTER
;WAY TO DO IT OTHER THAN DOING A PRESCAN OF THE FORMAT.
FMTENC: SETZM FMT.PC ;CLEAR PREV CHAR
MOVE T1,USR.SZ ;GET SIZE OF FORMAT STRING
IMULI T1,5 ;GET # CHARS
MOVEM T1,FMT.SZ ;SAVE THE SIZE
ADDI T1,%FMTEN+5 ;PLUS A FEW FOR LINK, ADDR, & INDEF RPT
MOVNI P4,(T1) ;GET NEGATIVE SIZE
HRLZI P4,(P4) ;IN LEFT HALF FOR FORMAT LIST
PUSHJ P,%GTBLK ;GET SOME CORE
HRRI P4,-1(T1) ;CREATE A DECODED STACK PNTR
MOVEM T1,ENC.AD ;SAVE ADDR FOR EXECUTION
PUSH P4,[0] ;CLEAR "NEXT LINK" ADDR
PUSH P4,USR.AD ;SAVE THE ENCODED FORMAT ADDR
PUSH P4,[0] ;CLEAR INDEF RPT PNTR
MOVEM P4,FMT.LK ;SAVE THE CURRENT STACK PNTR
MOVEI T1,1(P4) ;GET ADDR FOR ENCODED CHARS
MOVEM T1,RPT.PT ;INIT INDEF RPT PNTR
MOVE T1,USR.AD ;GET FORMAT ADDR AGAIN
$BLDBP T1 ;Make 7-bit byte ptr.
MOVEM T1,FMT.BP ;Store it in FMT.BP
MOVEM T1,FMT.BG ;Store ptr to beginning of format
PUSHJ P,FMTPRC ;PROCESS FORMAT
MOVE T1,ENC.AD ;GET BLOCK ADDR
MOVE T2,RPT.PT ;GET INDEF RPT PNTR
MOVEM T2,%FMTRP(T1) ;SAVE IT IN BLOCK
POPJ P,
;FMTINT - INITIALIZE THE FORMAT PARAMETERS. THE DIGIT COLLECTOR
;IS SET UP TO POINT TO THE REPEAT COUNT, THE SIGN IS
;SET TO +, AND THE TEMP FMT DATABASE IS CLEARED.
FMTINT: SETZM FMT.DB ;CLEAR 1ST DATABASE WORD
MOVE T1,[FMT.DB,,FMT.DB+1] ;CLEAR REST WITH BLT
BLT T1,FMT.EN
MOVEI T1,1 ;SET SIGN TO 1
MOVEM T1,FMT.SG
XMOVEI T1,FMT.RP ;SET TO COLLECT REPEAT COUNT
MOVEM T1,NUM.AD
POPJ P,
;FMTPRC - THIS IS THE FORMAT PROCESSOR OR ENCODER. EACH CHARACTER
;(OTHER THAN IN QUOTED STRINGS AND HOLLERITH CONSTANTS) ARE CONVERTED
;TO SIXBIT. THE RESULTING VALUE IS USED AS AN INDEX INTO A TABLE
;GIVING A SET OF FLAGS (LEFT HALF) AND POSSIBLY AN ADDRESS OF
;A WORD WHICH MAY HAVE THE ADDRESS OF A SPECIAL PROCESSING ROUTINE
;FOR THAT CHARACTER. FOR INSTANCE, THE TABLE ENTRY FOR LEFT PAREN
;HAS FDFLG IN THE LEFT HALF, WHICH INDICATES THAT ANY PREVIOUS DATA
;ENCOUNTERED SHOULD BE ENCODED INTO A FORMAT WORD AND REGISTERED INTO
;THE ENCODED FORMAT. IT HAS THE ADDRESS "RPRFMT" IN THE RIGHT HALF.
;"RPRFMT" CONTAINS THE ADDRESS OF THE LEFT PAREN ENCODING SUBROUTINE - LPRENC.
;IF "REGFLG" IS ON IN THE LEFT HALF OF THE TABLE ENTRY, IT MEANS THAT
;THE CHARACTER IS A "MAIN" FORMAT CHARACTER, THAT IS, IT WILL EVENTUALLY
;BE ENCODED AS A WORD IN THE ENCODED FORMAT AFTER
;ITS WIDTH, DECIMAL WIDTH, EXPONENT WIDTH, AND REPEAT COUNT ARE COLLECTED.
FMTPRC: PUSHJ P,FMTINT ;INIT DATABASE
FMTLP: SKIPG FMT.SZ ;ANYTHING LEFT?
JRST REGRP ;NO. FAKE A RIGHT PAREN
PUSHJ P,GTFCHR ;GET A CHAR
PUSHJ P,SIXVRT ;CONVERT TO SIXBIT
MOVEI P1,(T1) ;COPY IT
MOVEM P1,FMT.CC ;SAVE AS CURRENT CHAR
SKIPN FMT.CT(P1) ;ANY STUFF?
JRST FMTERR ;NO. BAD CHAR
PUSHJ P,ETEST ;SPECIAL TEST FOR E-FORMAT
MOVE P3,FMT.CT(P1) ;GET FLAGS
TXNE P3,FDFLG ;DELIMITER?
PUSHJ P,FMTCMP ;YES. COMPILE PREV FORMAT
TXNN P3,REGFLG ;REGISTER THE CHAR?
JRST NOREG ;NO
SKIPE FMT.WD ;IS THE FORMAT WIDTH ZERO?
$ECALL ARC,%ABORT ;NO, AMBIGUOUS REPEAT COUNT
SKIPE FMT.CH ;ANY LEFTOVER FORMAT CHAR?
PUSHJ P,FMTCMP ;YES. COMPILE PREV FORMAT
XMOVEI T1,FMT.WD ;SET TO COLLECT FORMAT WIDTH
MOVEM T1,NUM.AD
MOVE T1,FMT.SG ;ACCUMULATE THE SIGN
IMULM T1,FMT.RP ;INTO THE REPEAT COUNT
MOVEM P1,FMT.CH ;SAVE THE CHAR AWAY
NOREG: HRRZ P3,FMT.CT(P1) ;GET TABLE ADDR
JUMPE P3,FMTLP ;BACK IF NO DISPATCHES
HRRZ T1,(P3) ;GET ADDR OF DISPATCH
JUMPE T1,FMTLP ;BACK IF NO ADDR
PUSHJ P,(T1) ;IF ADDR, DO IT
JRST FMTLP ;BACK FOR MORE
POPJ P, ;RECURSIVE RETURN
REGRP: PUSHJ P,FMTCMP ;COMPILE ANY INCOMPLETE FORMAT
PUSHJ P,RPRENC ;FAKE A RIGHT PAREN
JFCL ;ALWAYS SKIP RETURNS
POPJ P,
ETEST: CAIE P1,'E' ;IS IT AN 'E'?
POPJ P, ;NO. LEAVE
MOVE T2,FMT.CH ;GET THE FORMAT CHAR
CAIE T2,'D' ;YES. IS IT A "D"
CAIN T2,'E' ;OR AN 'E'?
JRST ASMEXW ;YES. SET FOR EXPONENT WIDTH
CAIE T2,'G' ;SAME FOR 'G'
POPJ P, ;NO. LEAVE
ASMEXW: XMOVEI T1,FMT.EW ;ROUTE DIGITS TO EXP WIDTH
MOVEM T1,NUM.AD
EXPLP: SETZ P1, ;MAKE THE CHAR A SPACE
SKIPN FMT.SZ ;ANY CHARS LEFT?
PJRST FMTCMP ;NO. COMPILE THE FORMAT
PUSHJ P,GTFCHR ;YES. GET ONE
PUSHJ P,SIXVRT ;CONVERT TO SIXBIT
MOVEI P1,(T1) ;COPY THE CHAR
CAIG P1,'9' ;IS IT A DIGIT?
CAIGE P1,'0'
PJRST FMTCMP ;NO. GO USE AS NEXT CHAR
PUSHJ P,DIGENC ;YES. ACCUMULATE IT
JRST EXPLP ;AND GO BACK FOR MORE
;FMTSRH - SEARCHES FOR AN ENCODED FORMAT IN ONE OF THE
;LINKED LISTS (ADDR IN SAV.EF) MATCHING THE SPECIFIED
;USER'S FORMAT (ADDR IN USR.AD). RETURNS THE ADDR OF THE
;ENCODED FORMAT IN T1 IF FOUND, 0 IF NOT FOUND. ALSO, SAV.EF
;IS LEFT WITH THE ADDR OF THE FORMAT PREVIOUS TO
;ONE FOUND, OR THE ADDR OF THE LAST ENCODED FORMAT
;IN THE LINKED LIST, IF NOT FOUND. [NOTE: THE ORDER OF WHEN THE
;ADDRESS OF THE FORMAT IS SAVED IN SAV.EF (AFTER THE COMPARE
;AND EXIT) IS CRUCIAL FOR THE PROPER OPERATION OF FMTDEL,
;WHICH NEEDS THE ADDRESS PREVIOUS TO THE ONE MATCHED
;FOR RELINKING THE LIST.]
FMTSRH: MOVE T1,USR.AD ;GET FORMAT ADDR
IDIVI T1,FMTN ;HASH CODE...CHOOSE LIST
XMOVEI T1,FMT.LS(T2) ;GET ADDR OF PNTR TO BEG ENTRY
MOVEM T1,SAV.EF ;SAVE IT
FMTSR1: MOVE T1,SAV.EF ;GET ENC ADDR PNTR
MOVE T2,USR.AD ;AND UNENCODED ADDR
FSLP1: SKIPE T1,%FMTNX(T1) ;GET NEXT ADDR, RETURN IF NO MORE FORMATS
CAMN T2,%FMTAD(T1) ;ADDRESSES EQUAL?
POPJ P, ;YES. RETURN WITH ADDR IN T1
MOVEM T1,SAV.EF ;NO. SAVE NEW ADDR
JRST FSLP1 ;AND TRY AGAIN
;FORMAT COMPILATION - THROWS TOGETHER THE VARIOUS PARAMETERS
;ASSEMBLED SO FAR FOR A FORMAT CODE AND ASSEMBLES IT INTO
;AN ENCODED FORMAT WORD. SPECIAL HANDLING IS USED FOR THE
;CURRENT CHARACTER BEING "E" - THE ANSI-77 STANDARD
;ALLOWS THIS CHARACTER TO BE USED FOR BOTH E FORMAT AND
;FOR THE EXPONENT PART OF SCIENTIFIC NOTATION. THEREFORE
;IF THE CURRENT CHARACTER IS "E", WE CHECK IF THE FORMAT ABOUT
;TO BE COMPILED IS D,E,F OR G. IF SO, WE DEFER COMPILATION
;UNTIL COLLECTING THE EXPONENT WIDTH.
XENC: MOVEI T1,1 ;Incase "X" by itself
SKIPN FMT.RP
MOVEM T1,FMT.RP ;"X" = "1X" (DEC extension)
SKIPG FMT.RP ;X REPEAT COUNT MUST BE POSITIVE
$ECALL IRC,%ABORT ;IOERR (IRC,,,?,Illegal repeat count,,%ABORT)
FMTCMP: SKIPE T1,FMT.CH ;ANY FORMAT CHAR YET?
JRST FMTOK ;YES.
SKIPE FMT.RP ;NO. IS REPEAT COUNT ZERO?
$ECALL IRC,%ABORT ;NO. ILLEGAL REPEAT COUNT
POPJ P, ;YES. JUST IGNORE THE WHOLE THING
FMTOK: SETZM ENC.WD ;CLEAR THE ENCODED WORD
SKIPGE T1,FMT.WD ;FIELD WIDTH MUST BE POSITIVE
$ECALL IFW,%ABORT ;NEGATIVE IS FATAL
DPB T1,WIDPNT ;RECORD IT
MOVE T2,FMT.DW ;GET DECIMAL WIDTH
DPB T2,DECPNT
DMOVE T1,FMT.EW ;AND EXPONENT WIDTH AND REPEAT COUNT
DPB T1,EWPNT
DPB T2,RPTPNT
MOVE T1,FMT.CH ;AND FORMAT CODE
DPB T1,CODPNT
PUSH P4,ENC.WD ;STORE WORD ON STACK
PJRST FMTINT ;INITIALIZE THE DATABASE
;SIXVRT - CONVERTS ASCII CHARACTERS FROM THE FORMAT STATEMENT
;TO SIXBIT. CONVERTS ALL CRUD CHARACTERS (.LT.SPACE) TO SPACE.
SIXVRT: CAILE T1,140 ;LOWER CASE?
SUBI T1,40 ;YES. CONVERT TO UPPER
CAIGE T1,40 ;CONTROL CHAR?
MOVEI T1,40 ;YES. CONVERT TO SPACE
SUBI T1,40 ;CONVERT TO SIXBIT
POPJ P,
;RIGHT PAREN ENCODER - A RIGHT PAREN IS TRANSLATED INTO A ZERO
;WORD DROPPED ONTO THE STACK. SINCE THE FORMAT ENCODER IS RECURSIVE,
;THE RETURN FROM THIS SUBROUTINE IS ALWAYS A SKIP RETURN TO SPECIFY
;A RECURSIVE RETURN
RPRENC: PUSH P4,[0] ;DROP A ZERO ON THE STACK
PJRST %POPJ1 ;AND SKIP RETURN
;THIS ROUTINE IS CALLED BY I,O, AND Z FORMATS. THE ANSI STANDARD
;SPECIFIES THAT A FORMAT SUCH AS "I5.0" MEANS THAT NO DIGITS ARE
;PRINTED IF THE VALUE OF THE VARIABLE IS ZERO. THE DEFAULT FOR
;A FORMAT SUCH AS "I5" IS AT LEAST ONE DIGIT PRINTED. THUS THIS
;ROUTINE MUST BE CALLED TO SET THE DEFAULT NUMBER OF CHARACTERS
;PRINTED TO 1; WHEN A PERIOD IS ENCOUNTERED IT IS RESET TO ZERO
;TO PROPERLY COLLECT THE DIGITS.
MENC: MOVEI T1,1 ;SET DEFAULT FOR I,O,Z TO 1
MOVEM T1,FMT.DW ;FOR DECIMAL WIDTH
POPJ P,
;PERIOD ENCODING - UPON ENCOUNTERING A PERIOD, THE DECIMAL WIDTH
;(POSSIBLY SET TO NON-ZERO DEFAULT) IS CLEARED, AND THE DIGIT
;COLLECTER IS SET TO POINT TO THE DECIMAL WIDTH
PERENC: SETZM FMT.DW ;CLEAR DEC WIDTH
XMOVEI T1,FMT.DW ;POINT DIGACC AT DEC WIDTH
MOVEM T1,NUM.AD
POPJ P,
;DIGENC - THE DIGIT ENCODER. NUM.AD POINTS TO THE CURRENT
;DIGIT COLLECTOR.
DIGENC: MOVE T1,@NUM.AD ;GET ACC NUM
IMULI T1,12 ;MUL BY 10
ADDI T1,-20(P1) ;ADD IT IN
MOVEM T1,@NUM.AD ;SAVE IT AGAIN
POPJ P,
;LPRENC - THE LEFT PAREN ENCODER. A LEFT PAREN IS
;ENCODED AS A WORD CONTAINING THE NEGATIVE OF ITS REPEAT COUNT
;IN THE LEFT HALF, AND THE ADDRESS OF A "LINK" IN THE RIGHT HALF.
;A "LINK" IS THE ADDRESS OF THE 1ST WORD ENCODED AFTER THE RIGHT
;PAREN CORRESPONDING TO THE CURRENT LEFT PAREN. THE LEFT PAREN
;INITIATES A RECURSIVE CALL TO THE FORMAT ENCODER, AND THE LINK
;IS ESTABLISHED AFTER THE RETURN FROM THIS RECURSIVE CALL.
;UPON RETURNING, WE MUST DO SOMETHING WHICH LOOKS RATHER CURIOUS - WE SAVE
;THE CURRENT LINK (THAT IS, LEFT PAREN) POINTER IN THE INDEFINITE REPEAT
;POINTER, UNLESS WE ARE AT THE TOP LEVEL. THIS HAS THE EFFECT OF POINTING
;TO THE LEFT PAREN WHICH MATCHES THE NEXT TO LAST RIGHT PAREN (WE AVOID
;RESETTING IT TO THE OUTERMOST PAREN (THE INITIAL SETTING) BY NOT SAVING
;THE NO-LINK ENTRY.
;IF, AFTER RETURNING, THE SAVED FORMAT STACK ADDRESS IS THE
;BEGINNING OF THE FORMAT STACK, WE HAVE REACHED THE END OF
;THE FORMAT, SO THE LINK IS SET TO ZERO. IN THIS CASE,
;WE ALSO SKIP RETURN, TO INDICATE A RECURSIVE
;RETURN, AND THUS THE END OF ENCODING.
LPRENC: SKIPE T1,FMT.CH ;ANY PREVIOUS FORMAT CHARACTER?
PUSHJ P,FMTCMP ;YES. PROCESS IT
PUSH P,P4 ;PUSH CURRENT STACK PNTR
SKIPN T1,FMT.RP ;GET LATEST REPEAT COUNT
MOVEI T1,1 ;ASSUME COUNT OF 1 IF 0
MOVNI T1,(T1) ;NEGATE IT
HRLZI T1,(T1) ;-REPEAT COUNT,,0 FOR NOW
PUSH P4,T1 ;SAVE ON STACK
PUSHJ P,FMTPRC ;RECURSIVE CALL
POP P,T2 ;GET FORMAT LINK ADDR
CAMN T2,FMT.LK ;IF LINK ADDR IS START ADDR
JRST %POPJ1 ;WE'RE DONE
MOVEI T1,1(P4) ;NEXT ADDR IS CONTINUATION
ADDI T2,1 ;POINT TO THE REPEAT WORD
HRRM T1,(T2) ;SAVE IT IN LINK
HRRZM T2,RPT.PT ;SAVE LOOP ADDR FOR INDEF RPT
POPJ P,
;BENC - THE B FORMAT ENCODER - BN FORMAT IS ENCODED AS A 'B' FOR
;THE FORMAT CHARACTER AND "N" FOR THE WIDTH. BZ IS ENCODED WITH
;A "Z" FOR THE FORMAT WIDTH.
BENC: PUSHJ P,GTFCHR ;GET FORMAT CHAR
CAIE T1,"N" ;N OR Z?
CAIN T1,"Z"
JRST GOTNZ ;YES, OK
JRST FMTERR ;NO. ERROR
GOTNZ: MOVEM T1,FMT.WD ;SAVE AS WIDTH FIELD
PJRST FMTCMP ;COMPILE IT
;A MINUS IN THE FORMAT MERELY NEGATES THE SIGN. THIS ALSO ALLOWS
;FOR MULTIPLE NEGATIVE SIGNS TO CANCEL EACH OTHER, A RESULT I'M NOT
;SURE IS DESIRABLE...
MINENC: MOVNS FMT.SG ;NEGATE THE SIGN
POPJ P,
;SENC - FOR S,SS, &SP FORMATS. AN "S" OR "P" ARE ENCODED
;INTO THE WIDTH POSITION OF THE FORMAT WORD.
SENC: PUSHJ P,GTFCHR ;GET A FORMAT CHAR
CAIE T1,"S" ;IS IT AN S
CAIN T1,"P" ;IS IT A P
JRST MATPS ;YES
MOVEM T1,FMT.PC ;NO. SAVE AS PREVIOUS CHAR
MOVEI T1,"S" ;DEFAULT IS AN S
MATPS: MOVEM T1,FMT.WD ;SAVE AS WIDTH
PJRST FMTCMP ;COMPILE IT
;HOLLERITH ENCODING - WE ARE ALLOWING ANY CHARACTERS WHATSOEVER
;IN HOLLERITH AND QUOTED STRINGS, SO WE USE THE ACTUAL BYTE
;PNTR INTO THE FORMAT STATEMENT TO RETRIEVE THE CHARS RATHER
;THAN THE SUBROUTINE GTFCHR. THE FORMAT WORD IS COMPILED AND THE
;BYTE POINTER IS SAVED AS A SECOND WORD IN THE FORMAT STACK.
HENC: SKIPG T1,FMT.RP ;GET THE REPEAT COUNT
; IOERR (IHC,,,?,Illegal Hollerith constant,,%ABORT)
$ECALL IHC,%ABORT
PUSH P,FMT.BP ;SAVE THE BYTE PNTR
HENCLP: IBP FMT.BP ;INCR PAST H CONSTANT
SOSL FMT.SZ ;QUIT IF NO MORE FORMAT
SOJG T1,HENCLP
MOVNI T1,(T1) ;GET NEG LEFT OVER
ADDM T1,FMT.RP ;AND REDUCE SIZE
PUSHJ P,FMTCMP ;COMPILE THE FORMAT
POP P,T1 ;GET THE BYTE PNTR AGAIN
PUSH P4,T1 ;SAVE THE B.P. ON ENCODED STACK
POPJ P,
;SIMILAR TO HOLLERITH, EXCEPT THE COUNT MUST EXCLUDE THE
;EXTRA SINGLE QUOTES WHEN THEY ARE PAIRED TO OUTPUT A SINGLE
;QUOTE OR APOSTROPHE. ALSO, IF A SINGLE QUOTE IS NOT
;FOLLOWED BY ANOTHER, IT IS THE END OF THE QUOTED STRING;
;HOWEVER, WE HAVE ALREADY RETRIEVED THE CHARACTER, SO WE HAVE TO
;SAVE IT FOR LATER.
SQENC: SETZM FMT.WD ;CLEAR WIDTH
PUSH P,FMT.BP ;SAVE THE B.P.
SQLP1: SOSGE FMT.SZ ;ANY CHARS LEFT?
JRST SQEDON ;NO. CLOSE THE QUOTE
ILDB T1,FMT.BP ;NON-CHECKING SCAN
CAIE T1,"'" ;SINGLE QUOTE?
JRST NOTSQ ;NOPE
SOSGE FMT.SZ ;ANY CHARS LEFT?
JRST SQEDON ;NO. CLOSE THE QUOTE
ILDB T1,FMT.BP ;GET THE NEXT CHAR
CAIE T1,"'" ;ANOTHER QUOTE?
JRST SQEDON ;NO. STOP
AOS FMT.WD ;YES. COUNT BOTH OF THEM
NOTSQ: AOS FMT.WD ;NO. INCR THE COUNT
JRST SQLP1 ;AND TRY FOR MORE
SQEDON: MOVEM T1,FMT.PC ;NO. SAVE AS PREVIOUS CHAR
PUSHJ P,FMTCMP ;COMPILE THE FORMAT
POP P,T1 ;GET THE BYTE PNTR
PUSH P4,T1 ;STORE ON STACK
POPJ P,
;T FORMAT - THE ANSI STANDARD HAS CREATED 2 MORE CONFUSING FORMATS -
;TR AND TL (TAB RIGHT AND TAB LEFT). SINCE WE ONLY HAVE A SIXBIT
;CHARACTER POSITION FOR THE FORMAT CHAR, WE STORE THE "R" OR "L"
;IN THE DECIMAL WIDTH PORTION OF THE FORMAT WORD.
TENC: PUSHJ P,GTFCHR ;GET NEXT CHAR
CAIE T1,"L" ;L OR R
CAIN T1,"R"
JRST GOTLR ;YES
MOVEM T1,FMT.PC ;NO. SAVE THE CHAR FOR LATER
POPJ P,
GOTLR: PUSHJ P,SIXVRT ;CONVERT TO SIXBIT
MOVEM T1,FMT.DW ;SAVE AS DECIMAL WIDTH
POPJ P,
;THIS IS THE LIST OF EXECUTION/ENCODING ADDRESSES. LH=EXECUTION ADDR,
;RH=ENCODING ADDR. IF THERE IS NO ENCODING ADDR, IT
;MEANS THERE IS NO SPECIAL ENCODING, AND IS HANDLED BY THE
;ENCODER DEFAULTING MECHANISMS AND THE FLAGS IN FMT.CT.
COLFMT: COLEXE,,FMTCMP
SLHFMT: SLHEXE,,FMTCMP
DOLFMT: DOLEX,,FMTCMP
MINFMT: MINENC
DIGFMT: DIGENC
LPRFMT: LPRENC
RPRFMT: RPRENC
PERFMT: PERENC
SQFMT: SQEXEC,,SQENC
VARFMT: VAREXE,,0
AFMT: AEXEC,,0
BFMT: BEXEC,,BENC
DFMT: DEXEC,,0
EFMT: EEXEC,,0
FFMT: FEXEC,,0
GFMT: GEXEC,,0
HFMT: HEXEC,,HENC
IFMT: IEXEC,,MENC
LFMT: LEXEC,,0
OFMT: OEXEC,,0
PFMT: PEXEC,,FMTCMP
QFMT: QEXEC,,FMTCMP
RFMT: REXEC,,0
SFMT: SEXEC,,SENC
TFMT: TEXEC,,TENC
XFMT: XEXEC,,XENC
ZFMT: ZEXEC,,0
;EXECUTION TRANSFER VECTORS - THIS IS A TABLE OF
;ROUTINE ADDRESSES. THE LEFT HALF OF EACH WORD
;IS THE ADDRESS FOR INPUT, THE RIGHT FOR OUTPUT.
COLEXE: NOEXEC,,CHKDAT
SLHEXE: %IREC,,%ORECS
DOLEX: NOCR,,NOCR
SQEXEC: SQIN,,SQOUT
VAREXE: GETVAR,,GETVAR
AEXEC: %ALPHI,,%ALPHO
BEXEC: BNZ,,BNZ
DEXEC: %DIRT,,%DOUBT
EEXEC: %ERIN,,%EOUT
FEXEC: %FLIRT,,%FLOUT
GEXEC: GIN,,GOUT
HEXEC: HIN,,HOUT
IEXEC: %INTI,,%INTO
LEXEC: %LINT,,%LOUT
OEXEC: %OCTI,,%OCTO
PEXEC: PFACT,,PFACT
QEXEC: QIN,,QOUT
REXEC: %RIGHI,,%RIGHO
SEXEC: SSP,,SSP
TEXEC: TABREC,,TABREC
XEXEC: POSREC,,POSREC
ZEXEC: %HEXI,,%HEXO
;G-FORMAT CONVERSION ROUTINE ADDRESS TABLE.
;LH=INPUT, RH=OUTPUT
GTAB: %GINTI,,%GINTO ;NO TYPE GIVEN
%GLINT,,%GLOUT ;LOGICAL
%GINTI,,%GINTO ;INTEGER
NOEXEC,,NOEXEC ;UNDEFINED
%GRIN,,%GROUT ;REAL
NOEXEC,,NOEXEC ;UNDEFINED
%GOCTI,,%GOCTO ;OCTAL
NOEXEC,,NOEXEC ;LABEL
%GRIN,,%GROUT ;DOUBLE REAL
%GINTI,,%GINTO ;DOUBLE INTEGER
%OCTI,,%OCTO ;DOUBLE OCTAL
%GRIN,,%GROUT ;EXTENDED DOUBLE REAL
%GRIN,,%GROUT ;COMPLEX
NOEXEC,,NOEXEC ;BYTE STRING
NOEXEC,,NOEXEC ;CHARACTER
NOEXEC,,NOEXEC ;ASCIZ
NOEXEC:
GETVAR: POPJ P,
;THIS IS THE CALL TO FORMAT EXECUTION, EXEPRC.
FMTEXC: SETZM ENC.RP ;CLEAR LOOP REPEAT COUNT
SETZM ENC.LR ;AND LOCAL REPEAT COUNT
SETZM FMT.LK ;AND LINK WORD
SETZM SCL.SV ;CLEAR SCALE FACTOR
SETZM FMT.IU ;CLEAR I/O LIST USED FLAG
MOVE T2,FLAGS(D) ;T2= DDB flags
TXZ T2,D%SP+D%BZ ;Default is BN and SS
LOAD T1,BLNK(U) ;UNLESS SET OTHERWISE IN DDB
CAIN T1,BL.ZERO ;BLANK=ZERO?
TXO T2,D%BZ ;YES, SET BZ
MOVEM T2,FLAGS(D) ;Set new DDB flags
MOVE T1,ENC.AD ;GET ENCODED FORMAT ADDR
ADDI T1,%FMTEN ;POINT TO 1ST FMT WORD
MOVEM T1,ENC.PT ;SAVE IN STACK PNTR
PUSHJ P,EXEPRC ;EXECUTE THE FORMAT
SKIPN ENC.PT ;WAS I/O ABORTED?
POPJ P, ;YES. LEAVE (NO INDEF RPT)
EXELP: SKIPE IO.ADR ;ANY I/O ADDR READY?
JRST EXEOK ;YES
PUSHJ P,%%GETIO ;GET MORE I/O ADDR
SKIPN IO.ADR ;ANY MORE I/O LIST?
POPJ P, ;NO. LEAVE
EXEOK: SKIPN FMT.IU ;DATA USED BY LAST SCAN?
JRST FMTER2 ;NO. GIVE WARNING AND EXIT
MOVEI T1,SLHEXE ;EXECUTE EOL FOR EACH REPEAT
PUSHJ P,DOEXE
MOVE T1,ENC.AD ;GET ENCODED BLOCK ADDR
MOVE T1,%FMTRP(T1) ;GET INDEF RPT PNTR
MOVEM T1,ENC.PT ;FOR FORMAT STACK
SETZM ENC.RP ;CLEAR LOOP REPEAT COUNT
SETZM ENC.LR ;AND LOCAL REPEAT COUNT
SETZM FMT.LK ;CLEAR THE FORMAT LINK
SETZM FMT.IU ;CLEAR I/O LIST ENTRY USED FLAG
PUSHJ P,EXEPRC ;GO EXECUTE FORMAT
JRST EXELP ;GO BACK FOR MORE
FMTER2: ;IOERR (DLF,,,%,Data in IO list but not in format,,%ABORT)
$ECALL DLF,%ABORT
USEIO: SETZM IO.ADR ;CLEAR LAST I/O ADDR
PUSHJ P,%%GETIO ;GET ANOTHER
SKIPE IO.ADR ;GOT ANOTHER?
JRST USEIO ;YES. SCRAP IT
SETZM ENC.PT ;STOP EXECUTION, JUST IN CASE
POPJ P, ;NO. LEAVE
;EXEPRC - THE ENCODED FORMAT EXECUTIONER (SIMILAR TO
;LORD HIGH EXECUTIONER). THIS IS A TOTALLY RECURSIVE EXECUTION SEQUENCE.
;STARTING AT THE GIVEN FORMAT STACK POINTER, ENCODED WORDS ARE
;LOADED, AND DEPENDING ON THE FORMAT CODE, A DATA ITEM MAY BE RETRIEVED,
;AND THEN THE PROPER SUBROUTINE IS CALLED. THE FORMAT ENCODER HAS
;ENCODED LEFT PARENS AS WORDS WITH A NEGATIVE LEFT HALF (NEGATIVE REPEAT COUNT),
;AND A LINK TO THE FORMAT CODES AFTER THE LOOP IN THE RIGHT HALF. THE FIRST
;ENCODED LEFT PAREN HAS A ZERO LINK, AS THERE ARE NO FORMAT ITEMS AFTER
;ITS MATCHING RIGHT PAREN. HERE, WHEN A NEGATIVE ENTRY (AN ENCODED LEFT PAREN)
;IS ENCOUNTERED, THE EXECUTION SEQUENCE IS CALLED RECURSIVELY, SAVING
;THE CURRENT VALUE OF THE LOOP REPEAT COUNT AND CURRENT LEFT PAREN
;ADDRESS (REFFERED TO AS THE "LINK" ADDRESS) ON THE PUSHDOWN STACK.
;UPON RETURN, THE FORMAT STACK POINTER IS SET TO THE ADDRESS SPECIFIED BY
;THE ENCODED LEFT PAREN (IN FMT.LK).
;AT THIS POINT, WE MUST DO SOMETHING WHICH LOOKS RATHER CURIOUS - WE SAVE
;THE CURRENT LINK (THAT IS, LEFT PAREN) POINTER IN THE INDEFINITE REPEAT
;POINTER, UNLESS THERE IS NO LINK (RH=0). THIS HAS THE EFFECT OF POINTING
;TO THE LEFT PAREN WHICH MATCHES THE NEXT TO LAST RIGHT PAREN (WE AVOID
;RESETTING IT TO THE OUTERMOST PAREN (THE INITIAL SETTING) BY NOT SAVING
;THE NO-LINK ENTRY).
;THE PATHOLOGICAL CASES "FALL OUT" FROM THIS PROCEDURE - IF THE
;INITIAL LEFT PAREN IS MISSING, FMT.LK, THE LINK, WILL BE ZERO WHEN
;THE MATCHING RIGHT PAREN (OR FAKE RIGHT PAREN PLACED THERE BY THE
;FORMAT ENCODER) IS EXECUTED. THIS HAS BEEN CODED TO END FORMAT EXECUTION.
EXEPRC: SKIPN ENC.PT ;IF PNTR IS 0
POPJ P, ;WE ABORTED I/O
SKIPL @ENC.PT ;PAREN?
JRST EXENRM ;NO. NORMAL EXECUTION
PUSH P,ENC.RP ;YES. SAVE OLD REPEAT COUNT
PUSH P,FMT.LK ;AND LINK ADDR
HLRE T1,@ENC.PT ;GET THE NEW REPEAT COUNT
MOVN T1,T1 ;POSITIVE
MOVEM T1,ENC.RP ;SAVE IT
MOVE T1,ENC.PT ;GET THE PAREN WORD
MOVEM T1,FMT.LK ;SAVE FOR LINK
AOS ENC.PT ;INC THE FORMAT PNTR
PUSHJ P,EXEPRC ;RECURSIVE CALL
SKIPN ENC.PT ;DID WE STOP?
JRST ENDEXE ;YES. LEAVE
MOVE T1,FMT.LK ;GET THE LINK
HRRZ T2,(T1) ;GET THE ADDR
JUMPE T2,ENDEXE ;DON'T STORE ZERO!
XMOVEI T2,(T2) ;GET SECTION NUMBER ALSO
MOVEM T2,ENC.PT ;LINK THE PROCESSOR
ENDEXE: POP P,FMT.LK ;RESTORE PREVIOUS LINK
POP P,ENC.RP ;AND REPEAT COUNT
JRST EXEPRC ;AND START AGAIN
EXENRM: SKIPN T1,@ENC.PT ;GET FORMAT WORD
JRST EXENLP ;HIT END OF LIST
MOVEM T1,ENC.WD ;SAVE FOR CODE RETRIEVAL
LDB T1,CODPNT ;GET FORMAT CHAR
MOVE T1,FMT.CT(T1) ;GET TABLE ENTRY
TXNN T1,IOLFLG ;DO WE NEED I/O LIST ENTRY?
JRST NODATA ;NO
MOVEM T1,IO.TBL ;Save flags and table entry for later
SKIPLE ENC.LR ;ANY LEFTOVER REPEAT COUNT?
JRST LROK ;YES. USE IT
LDB T1,RPTPNT ;NO. GET IT FROM FORMAT WORD
MOVEM T1,ENC.LR ;SAVE IT
LROK: SETOM FMT.IU ;YES, SET I/O LIST ENTRY USED FLAG
DATLP: SKIPN IO.ADR ;DO WE HAVE ADDR ALREADY?
JRST GETADR ;NO. GO GET IT
GOTADR: HRRZ T1,IO.TBL ;GET I/O ROUTINE PNTR
HLRZ T1,(T1) ;GET JUST EXEC ADDR
MOVE T0,FLAGS(D) ;Get DDB flags
TXNN T0,D%IO ;OUTPUT?
JRST DATIN ;NO. GO DO INPUT
HRRZ T1,(T1) ;GET OUTPUT SUBR ADDR
PUSHJ P,(T1) ;DO IT
JRST DATINC ;DID NOT END. GO INC DATA PNTR
POPJ P, ;WE HAVE BEEN TOLD TO STOP!
GETADR: PUSHJ P,%%GETIO ;NO. GET THE DATA ADDR
SKIPE IO.ADR ;DID WE GET IT?
JRST GOTADR ;YES.
SETZM ENC.PT ;NO. END EXECUTION
POPJ P,
DATIN: HLRZ T1,(T1) ;GET INPUT SUBR ADDR
PUSHJ P,(T1) ;DO IT
LDB T1,WIDPNT ;FREE FORMAT?
JUMPN T1,DATINC ;NO.
MOVE T1,IO.TBL ;Get flags and table entry
TXNE T1,SKPFLG ;YES. DID WE ACTUALLY READ DATA?
PUSHJ P,SFDEL ;YES. SCAN FOR NEXT DELIM
DATINC: SKIPN T1,IO.INC ;ADD OFFSET TO I/O ADDR
JRST CPXINC ;IF IT'S ZERO, ADD COMPLEX INCREMENT
DATIN2: ADDM T1,IO.ADR ;TO I/O ADDR
SOSG IO.NUM ;DECR LOCAL DATA COUNT
SETZM IO.ADR ;CLEAR I/O ADDR IF NONE LEFT
SOSLE ENC.LR ;DECR LOCAL REPEAT COUNT
JRST DATLP ;MORE TO GO
AOS ENC.PT ;ON TO NEXT FORMAT
JRST EXEPRC ;AND BACK FOR MORE FORMAT
CPXINC: HRRE T1,CP.INC ;GO TO IMAG PART OR NEXT ENTRY
MOVSS CP.INC ;AND PREPARE FOR NEXT TIME
JRST DATIN2 ;BACK TO USUAL INCREMENT CODE
EXENLP: SKIPE T1,FMT.LK ;GET ADDR BEFORE START
SOSG ENC.RP ;DECR REPEAT COUNT
POPJ P, ;END OF LIST OR COUNT EXHAUSTED
ADDI T1,1 ;RESET PNTR
MOVEM T1,ENC.PT ;TO LOOP
JRST EXEPRC ;START AGAIN
NODATA: HRRZ T1,T1 ;GET I/O ROUTINE PNTR
HLRZ T1,(T1) ;GET EXECUTION TABLE PNTR
PUSHJ P,DOEXE ;DO IT
AOS ENC.PT ;ON TO NEXT FORMAT
JRST EXEPRC
DOEXE: MOVE T1,(T1) ;GET THE ADDR PAIR
MOVE T0,FLAGS(D) ;Get DDB flags
TXNN T0,D%IO ;OUTPUT?
HLRZ T1,T1 ;NO. GET THE INPUT ADDR
HRRZ T1,T1 ;CLEAR OUT THE LEFT HALF
PJRST (T1) ;DO IT
;G-FORMAT I/O. USES THE DATA TYPE TO FIGURE OUT WHAT TO DO
GIN: MOVE T1,IO.TYP ;GET VARIABLE TYPE
HLRZ T1,GTAB(T1) ;GET I/O CONV ADDRESS
PJRST (T1) ;DO IT
GOUT: MOVE T1,IO.TYP ;GET VARIABLE TYPE
HRRZ T1,GTAB(T1) ;GET OUTPUT CONV ADDRESS
PJRST (T1) ;DO IT
;SCAN FOR A DELIMITER - FOR "FREE-FORMAT" INPUT,
;WE HAVE TO SCAN UNTIL WE REACH A "DELIMITER" FOR THIS TYPE
;OF INPUT, TO AVOID GETTING FAKE NULL VALUES FOR SUCH THINGS
;AS <DATA><SPACES><COMMA><SPACES><DATA>. THE DELIMITERS FOR
;FREE-FORMAT ARE ANY NON-BLANK CHARACTERS AND END-OF-LINE.
;IF THE NON-BLANK CHARACTER IS NOT A COMMA, THE BYTE POINTER
;IS BACKED UP VIA A CALL TO %IBACK SO THAT THE NEXT CALL
;TO %IBYTE WILL GET IT.
SFDEL: PUSHJ P,%IBYTC ;GET CURRENT CHAR
JRST DELGOT ;SKIP NEW CHAR
SFDLP1: PUSHJ P,%IBYTE ;GET NEXT CHAR
DELGOT: MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%EOR ;REACH END OF RECORD?
POPJ P, ;YES
CAIE T1," " ;SKIP SPACES AND TABS
CAIN T1," "
JRST SFDLP1
CAIE T1,"," ;LEAVE ON COMMA
JRST %IBACK ;ELSE PUSH THE POINTER BACK
POPJ P,
;DOLLAR SIGN EXECUTION (SOUNDS LIKE SOCIALISM OR SOMETHING)...
;IGNORE IT ON INPUT, CALL SPECIAL ROUTINE ON OUTPUT WHICH OUTPUTS
;THE RECORD WITHOUT A CARRIAGE RETURN FOR OUTPUT.
NOCR: MOVX T0,D%STCR ;Suppress trailing CR
IORM T0,FLAGS(D)
POPJ P,
;COLON - FOR OUTPUT, IF THE I/O LIST IS DONE, CLEAR THE ENCODED STACK POINTER
;AS A SIGNAL TO THE FORMAT EXECUTION TO STOP.
CHKDAT: SKIPN IO.ADR ;DO WE HAVE I/O ADDR?
PUSHJ P,%%GETIO ;NO. GET NEXT I/O ADDR
SKIPE IO.ADR ;DID WE GET IT?
POPJ P, ;YES. EVERYTHING'S FINE
SETZM ENC.PT ;NO. END EXECUTION
AOS (P) ;AND SKIP RETURN
POPJ P,
;BNZ - BN AND BZ FORMAT
;IF THE LETTER AFTER THE B WAS A "Z", TURN ON THE
;BZ FORMAT FLAG, WHICH FORCES BLANKS TO BE INTERPRETED
;AS ZEROES FOR FIXED FORMAT FIELDS. OTHERWISE TURN OFF
;THE BZ FORMAT FLAG
BNZ: LDB T1,WIDPNT ;GET ARG
MOVX T0,D%BZ ;Assume not Z
ANDCAM T0,FLAGS(D)
CAIN T1,"Z"
IORM T0,FLAGS(D) ;Was "Z", set flag
POPJ P,
;H-FORMAT - THE BYTE POINTER TO THE HOLLERITH STRING HAS
;BEEN STORED IN THE NEXT ENTRY IN THE FORMAT STACK. THE
;NUMBER OF CHARACTERS IS IN THE WIDTH FIELD.
HOUT: AOS ENC.PT ;INCR TO BYTE PNTR
LDB T2,RPTPNT ;GET # CHARS
MOVE T3,@ENC.PT ;Get byte ptr
HOUTLP: ILDB T1,T3 ;GET CHAR
PUSHJ P,%OBYTE ;OUTPUT IT
SOJG T2,HOUTLP ;BACK FOR MORE
POPJ P,
;Q FORMAT - RETURNS THE NUMBER OF CHARS LEFT IN THE RECORD
;INTO THE SPECIFIED VARIABLE (INTEGER!).
QIN: SKIPGE T1,IRCNT(D) ;GET # CHARS LEFT
SETZ T1, ;PAST END OF RECORD, RETURN 0
MOVEM T1,@IO.ADR ;PUT INTO USER'S VARIABLE
; POPJ P,
QOUT: POPJ P,
;P FORMAT - SETS THE SCALE FACTOR. THE SCALE FACTOR
;HAS BEEN STORED AS IF IT WERE A REPEAT COUNT, SO WE
;HAVE TO DO SOME CONTORTIONS IN ORDER TO EXTEND THE SIGN
PFACT: LDB T1,RPTPNT ;GET REPEAT COUNT
TRNE T1,400 ;SIGN BIT ON?
ORCMI T1,777 ;YES. TURN THE REST ON
MOVEM T1,SCL.SV ;SAVE IT
POPJ P,
;SSP - HANDLES S,SP, AND SS FORMATS.
;THE DEC IMPLEMENTATION OF THIS FORMAT MEANS THAT S FORMAT
;MEANS SS, SINCE WE DO NOT OUTPUT A PLUS SIGN
;UNDER NORMAL CIRCUMSTANCES. SO THERE IS A SINGLE FLAG, WHICH JUST
;SAYS WHETHER OR NOT TO FORCE A PLUS SIGN (AND THEN ONLY IF IT WILL
;FIT!), CORRESPONDING TO SP AND SS.
SSP: LDB T1,WIDPNT ;GET THE CODE
MOVX T0,D%SP ;Assume not "P"
ANDCAM T0,FLAGS(D)
CAIN T1,"P" ;IS IT P?
IORM T0,FLAGS(D) ;Yes, set flag
POPJ P,
;T FORMAT - POSITIONS RECORD POINTER.
;ARGUMENT IS IN WIDTH FIELD
TABREC: LDB P3,DECPNT ;GET L OR R
JUMPN P3,LRPOS ;GO PROCESS THEM IF THERE
LDB T1,WIDPNT ;GET VALUE
JUMPG T1,%SPOS ;SEND REQUESTED POSITION
MOVEI T1,1 ;IF LESS THAN 1, SET TO 1
PJRST %SPOS
LRPOS: PUSHJ P,%RPOS ;GET CURRENT POSITION
LDB T2,WIDPNT ;GET FORMAT ARG
CAIN P3,'L' ;IS IT TAB LEFT?
MOVNI T2,(T2) ;YES. NEGATE TAB
ADD T1,T2 ;AND SET NEW POSITION
JUMPG T1,%SPOS ;SEND REQUESTED POSITION
MOVEI T1,1 ;REQ COL 1 IF OFF LEFT OF RECORD
PJRST %SPOS
;X FORMAT - SIMILAR TO T FORMAT, BUT WITH REPEAT COUNT INSTEAD
;OF WIDTH FOR ITS VALUE
POSREC: PUSHJ P,%RPOS ;GET CURRENT RECORD POSITION
LDB T2,RPTPNT ;GET ARG OF X-FORMAT
ADD T1,T2 ;ADD THE 2
JUMPG T1,%SPOS ;INCR TO POS WHERE WE WANT NEXT CHAR
MOVEI T1,1 ;BUT IF NEG OR ZERO
PJRST %SPOS ;JUST SUPPLY 1
;SINGLE QUOTE OUTPUT - LIKE HOLLERITH, THE BYTE POINTER IS STORED
;AS THE NEXT (1 OR 2) WORD ON THE FORMAT STACK, AND THE CHARACTER COUNT IS
;STORED AS THE WIDTH. UNLIKE HOLLERITH, DOUBLE APOSTROPHES MUST BE
;TURNED INTO SINGLE APOSTROPHES.
SQOUT: AOS ENC.PT ;INCR TO BYTE PNTR
LDB T2,WIDPNT ;GET THE # CHARS
JUMPE T2,SQODON ;DONE IF NO CHARS
MOVE T3,@ENC.PT ;Get the byte ptr.
SQOLP: ILDB T1,T3 ;GET CHAR
CAIE T1,"'" ;IS IT A QUOTE?
JRST PUTNSQ ;NO. GO OUTPUT IT
SOJLE T2,SQODON ;DECR AND LEAVE IF NO MORE
IBP T3 ;INCR PAST THE NEXT CHAR
PUTNSQ: PUSHJ P,%OBYTE ;AND PRINT CHAR
SOJG T2,SQOLP ;BACK FOR MORE
SQODON: POPJ P,
;SINGLE QUOTE INPUT - ALLOWS THE USER TO OVERWRITE A QUOTED STRING
;IN THE FORMAT STATEMENT. DISALLOWED BY THE ANSI STANDARD, BUT WE
;DO IT ANYWAY.
SQIN: AOS ENC.PT ;INCR TO BYTE POINTER
LDB T2,WIDPNT ;GET # CHARS TO INPUT
JRST HIN0 ;REST IS SAME AS HOLLERITH
;HOLLERITH INPUT - A STUPID WAY TO WRITE PROGRAMS, BUT ELLIOT
;ORGANICK USES IT AS AN EXAMPLE IN HIS INTRO TO FORTRAN! THE NUMBER
;OF CHARACTERS SPECIFIED IN THE FIELD ARE READ FROM THE INPUT RECORD
;AND WRITTEN INTO THE ORIGINAL FORMAT STATEMENT.
HIN: AOS ENC.PT ;INCR TO BYTE PNTR
LDB T2,RPTPNT ;GET # CHARS TO INPUT
HIN0: MOVE T3,@ENC.PT ;Get the byte ptr
HINLP: PUSHJ P,%IBYTE ;GET A CHAR
IDPB T1,T3 ;DEPOSIT INTO FORMAT
SOJG T2,HINLP ;BACK FOR MORE
POPJ P,
;GTFCHR - GET THE NEXT CHARACTER IN THE FORMAT.
;EXCEPT FOR H-FORMAT AND QUOTED STRINGS, WE DO NOT WANT
;NULL CHARACTERS FROM THE FORMAT STATEMENT. ADDITIONALLY,
;PROVISION HAS BEEN MADE IF WE READ TOO FAR WE SAVE THE
;CHARACTER READ AS THE "PREVIOUS CHAR" AND RETRIEVE IT THE
;NEXT TIME GTFCHR IS CALLED.
GTFCHR: SKIPE T1,FMT.PC ;Is there a previous char?
JRST PREVCH ;Yes, go clear it
NOPREV: SOSGE FMT.SZ ;ANY CHARS LEFT?
POPJ P, ;NO. RETURN WITH NULL
ILDB T1,FMT.BP ;GET A CHAR
JUMPE T1,NOPREV ;SKIP NULLS
CAILE T1,140 ;LOWER CASE?
SUBI T1,40 ;YES. CONVERT TO UPPER
POPJ P,
PREVCH: SETZM FMT.PC ;IF ONE, NOW CLEAR IT
POPJ P, ;SO WE WON'T GET IT AGAIN
FMTERR: ;IOERR (ILF,,,?,Illegal character in format,,%ABORT)
$ECALL ILF,%ABORT
FMTER3: $SNH
;ROUTINE TO CONVERT CALLING CONVENTIONS
;RETURN: IO.ADR = ADDRESS OF I/O ITEM
; IO.TYP = DATA TYPE
; ** WARNING: Smashes perm acs **
%%GETIO::
MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%EOI ;IO LIST ALREADY AT END?
POPJ P, ;YES. RETURN
NIOEND: PUSHJ P,%GETIO ;NO, GO GET IT
JUMPN T1,GETIO1 ;JUMP IF NOT END OF IO LIST
MOVX T0,D%EOI ;Flag it
IORM T0,FLAGS(D)
GETIO1: SETZM CP.INC ;CLEAR THE COMPLEX INCREMENT
MOVEM T1,IO.ADR ;STORE ADDRESS
MOVE T0,FLAGS(D)
TXNN T0,D%LSD ;LIST-DIRECTED?
CAIE T2,TP%CPX ;No, COMPLEX?
JRST NOTCPX ;LIST-DIRECTED OR NOT COMPLEX
MOVEI T2,TP%SPR ;YES. SUBSTITUTE REAL
ASH T3,1 ;DOUBLE COUNT
SUBI T4,1 ;PREPARE COMPLEX INCREMENT
HRLI T4,1
MOVSM T4,CP.INC ;[INCR-1,,1]
SETZ T4, ;AND ZERO STANDARD INCREMENT
NOTCPX: MOVEM T2,IO.TYP ;STORE TYPE
DMOVEM T3,IO.NUM ;AND COUNT AND INCREMENT
POPJ P, ;DONE
SEGMENT DATA
CP.INC: BLOCK 1
IO.ADR:: BLOCK 1
IO.TYP:: BLOCK 1
IO.NUM:: BLOCK 1 ;Do not split IO.NUM and IO.INC
IO.INC:: BLOCK 1
IO.INF:: BLOCK 1
IO.TBL: BLOCK 1 ;Save flags and table address in EXENRM
ILLEG.:: 0
SEGMENT CODE
PURGE $SEG$
END