ITS Muddle.
[pdp10-muddle.git] / MUDDLE / nprint.8
diff --git a/MUDDLE/nprint.8 b/MUDDLE/nprint.8
new file mode 100644 (file)
index 0000000..e719984
--- /dev/null
@@ -0,0 +1,799 @@
+TITLE  PRINTER ROUTINE FOR MUDDLE
+RELOCATABLE
+.INSRT DSK:MUDDLE >
+.GLOBAL        IPNAME,TYO,FIXB,FLOATB
+.GLOBAL BYTPNT,OPNCHN,CHRWRD,IDVAL,CHARGS,CHFRM,NONSPC
+
+FLAGS==0       ;REGISTER USED TO STORE FLAGS
+CARRET==15     ;CARRIAGE RETURN CHARACTER
+ESCHAR=="\     ;ESCAPE CHARACTER
+SPACE==40      ;SPACE CHARACTER
+ATMBIT=200000  ;BIT SWITCH FOR ATOM-NAME PRINT
+NOQBIT=020000  ;SWITCH FOR NO ESCAPING OF OUTPUT (PRINC)
+SEGBIT=010000  ;SWITCH TO INDICATE PRINTING A SEGMENT
+SPCBIT=004000  ;SWITCH TO INDICATE "PRINT" CALL (PUT A SPACE AFTER)
+FLTBIT=002000  ;SWITCH TO INDICATE "FLATSIZE" CALL
+HSHBIT=001000  ;SWITCH TO INDICATE "PHASH" CALL
+TERBIT=000400  ;SWITCH TO INDICATE "TERPRI" CALL
+
+P.STUF:        0
+
+PSYM:
+       EXCH A,P.STUFF
+       .VALUE [ASCIZ \1c\17.=P.STUF!\eQîP.STUF/\eQ!:VP \1c]
+       PUSH TP, (A)
+       PUSH TP, 1(A)
+       MCALL 1,PRINT
+       EXCH A,P.STUFF
+       POPJ P,
+
+P.=PUSHJ P, PSYM
+
+\fMFUNCTION     FLATSIZE,SUBR
+       DEFINE FLTMAX
+               2(AB)TERMIN
+       DEFINE FLTSIZ
+               0(TB)TERMIN
+;FLATSIZE TAKES TWO ARGUMENTS: THE FIRST IS AN OBJECT THE SECOND
+;IS THE MAXIMUM SIZE BEFORE IT GIVES UP AN RETURNS FALSE
+       ENTRY   2
+       HLRZ    A,2(AB)
+       CAIN    A,TFIX
+       JRST    FLAT1
+;IF THE SECOND ARGUMENT IS NOT FIXED POINT LOSE
+       PUSH    TP,$TATOM
+       PUSH    TP,MQUOTE WRONG-TYPE
+       JRST    CALER1
+
+FLAT1: PUSH    TP,$TFIX
+       PUSH    TP,[0]  ;THE VALUE IS ACCUMULATED IN FLTSIZ
+       PUSH    P,FLAGS
+       MOVSI   FLAGS,FLTBIT
+       MOVE    A,(AB)  ;IPRINT TAKES ITS ARGUMENT A AND B
+       MOVE    B,1(AB)
+       PUSHJ   P,IPRINT
+       MOVE    A,FLTSIZ
+       MOVE    B,FLTSIZ+1
+       JRST    FINIS
+
+MFUNCTION      PHASH,SUBR
+       DEFINE HSHMAX
+               2(AB)TERMIN
+       DEFINE HSHNUM
+               0(TB)TERMIN
+;PHASH TAKES TWO ARGUMENTS: THE FIRST IS AN OBJECT THE SECOND
+;IS THE MAXIMUM SIZE BEFORE IT GIVES UP AN RETURNS THE HASH NUMBER
+       ENTRY   2
+       HLRZ    A,2(AB)
+       CAIN    A,TFIX
+       JRST    HASH1
+;IF THE SECOND ARGUMENT IS NOT FIXED POINT LOSE
+       PUSH    TP,$TATOM
+       PUSH    TP,MQUOTE WRONG-TYPE
+       JRST    CALER1
+
+HASH1: PUSH    TP,$TFIX
+       PUSH    TP,[0]  ;THE VALUE IS ACCUMULATED IN HASHNUM
+       PUSH    P,FLAGS
+       MOVSI   FLAGS,HSHBIT
+       MOVE    A,(AB)  ;IPRINT TAKES ITS ARGUMENT A AND B
+       MOVE    B,1(AB)
+       PUSHJ   P,IPRINT
+       MOVE    A,HSHNUM
+       MOVE    B,HSHNUM+1
+       JRST    FINIS
+
+\fMFUNCTION     PRINT,SUBR
+       ENTRY   
+       PUSH    P,FLAGS ;SAVE THE FLAGS REGISTER
+       MOVSI   FLAGS,SPCBIT    ;INDICATE PRINTING OF SPACE WHEN DONE
+       JRST    PRIN01  ;CALL IPRINT AFTER SAVING STUFF
+
+MFUNCTION      PRINC,SUBR
+       ENTRY   
+       PUSH    P,FLAGS ;SAVE THE FLAGS REGISTER
+       MOVSI   FLAGS,NOQBIT    ;INDICATE PRINC (NO QUOTES OR ESCAPES)
+       JRST    PRIN01  ;CALL IPRINT AFTER SAVING STUFF
+
+MFUNCTION      PRIN1,SUBR
+       ENTRY   
+       PUSH    P,FLAGS ;SAVE FLAGS REGISTER
+       MOVEI   FLAGS,0 ;ZERO (TURN OFF) ALL FLAGS
+       JRST    PRIN01  ;CALL IPRINT AFTER SAVING STUFF
+
+
+MFUNCTION      TERPRI,SUBR
+       ENTRY
+       MOVSI   FLAGS,TERBIT+SPCBIT
+       JUMPGE  AB,DEFCHN       ;IF NO ARG GO GET CURRENT OUT-CHANNEL BINDING
+       CAMG    AB,[-2,,0]
+       JRST    WNA
+       PUSH    TP,$TFIX        ;SAVE ROOM ON STACK FOR ONE CHANNEL
+       PUSH    TP,[0]
+       MOVE    A,(AB)
+       MOVE    B,(AB)+1
+       JRST    COMPT
+
+\fPRIN01:       PUSH    P,C     ;SAVE REGISTERS C,D, AND E
+       PUSH    P,D
+       PUSH    P,E
+       PUSH    TP,$TFIX        ;LEAVE ROOM ON STACK FOR ONE CHANNEL
+       PUSH    TP,[0]
+
+       HLRZ    C,AB    ;GET THE AOBJN COUNT FROM AB
+       CAIN    C,-2    ;SKIP IF NOT JUST ONE ARGUMENT GIVEN
+       JRST    DEFCHN  ;ELSE USE EXISTING BINDING OF "OUTCHAN"
+       CAIE    C,-4    ;ELSE, THERE MUST BE ONLY TWO ARGUMENTS
+       JRST    ARGERR  ;MORE ARGUMENTS IS AN ERROR
+       MOVE    A,(AB)+2
+       MOVE    B,(AB)+3
+COMPT: CAME    A,$TLIST
+       JRST    BINDPT
+       SKIPN   C,(AB)3 ;EMPTY LIST ?
+       JRST    FINIS   ;IF SO, NO NEED TO CONTINUE
+LISTCK:        HRRZ    C,(C)   ;REST OF LIST
+       JUMPE   C,BINDPT        ;FINISHED ?
+       PUSH    TP,$TFIX        ;LEAVE ROOM ON STACK FOR THIS ADDITIONAL CHANNEL
+       PUSH    TP,[0]
+       JRST    LISTCK
+
+BINDPT:        PUSH    TP,[TATOM,,-1]
+       PUSH    TP,MQUOTE OUTCHAN
+       PUSH    TP,A    ;PUSH NEW OUT-CHANNEL
+       PUSH    TP,B
+       PUSH    TP,[0]
+       PUSH    TP,[0]
+       PUSH    P,FLAGS ;THESE WILL GET CLOBBERED BY SPECBIND
+       PUSHJ   P,SPECBIND
+       POP     P,FLAGS
+
+DEFCHN:        MOVE    B,MQUOTE OUTCHAN
+       MOVSI   A,TATOM
+       PUSHJ   P,IDVAL ;GET VALUE OF CHANNEL
+       SETZ    E,      ;CLEAR E FOR SINGLE CHANNEL ARGUMENTS
+       CAMN    A,$TCHAN        ;SKIP IF IT ISN'T A VALID SINGLE CHANNEL
+       JRST    SAVECH
+       CAME    A,$TLIST        ;SKIP IF IT IS A LIST OF CHANNELS
+       JRST    CHNERR  ;CAN'T HANDLE ANYTHING ELSE (FOR NOW)
+       SKIPA   E,B     ;SAVE LIST POINTER IN E
+LOOPCH:        ADDI    FLAGS,2 ;INCREMENT NUMBER OF CHANNELS COLLECTED
+       HLLZ    A,(E)   ;GET TYPE (SHOULD BE CHANNEL)
+       CAME    A,$TCHAN
+       JRST    CHNERR
+       MOVE    B,(E)+1 ;GET VALUE
+       HRRZ    E,(E)   ;UPDATE LIST POINTER
+
+SAVECH:        HRRZ    C,FLAGS ;GET CURRENT CHANNEL COUNT
+       ADDI    C,(TB)  ;APPROPRIATE STACK LOCATION
+       CAIN    C,(TP)+1        ;NEED MORE ROOM ON STACK FOR LIST ELEMENT CHANNELS ?
+       ADD     TP,[2,,2]       ;IF SO, GET MORE STACK ROOM
+       MOVEM   A,(C)   ;SAVE CHANNEL POINTER ON STACK
+       MOVEM   B,(C)+1
+       SKIPN   IOINS(B)        ;SKIP IF I/O INSTRUCTION IS NON-ZERO
+       PUSHJ   P,OPNCHN        ;ELSE TRY TO OPEN THE CHANNEL
+       JUMPE   B,CHNERR        ;ERROR IF IT CANNOT BE OPENED
+       MOVEI   B,DIRECT-1(B)   ;POINT TO DIRECTION
+       PUSHJ   P,CHRWRD
+       JFCL
+       CAME    B,[ASCII /PRINT/]       ;IS IT PRINT
+       JRST    CHNERR  ;ELSE IT IS AN ERROR
+       JUMPN   E,LOOPCH        ;IF MORE CHANNELS ON LIST, GO CONSIDER THEM
+       ADDI    FLAGS,2 ;MAKE FINAL UPDATE OF COUNT
+\f      MOVEI   A,CARRET        ;GET A CARRIAGE RETURN
+       TLNE    FLAGS,SPCBIT    ;TYPE IT ONLY IF BIT IS ONE (PRINT)
+       PUSHJ   P,PITYO
+       TLNE    FLAGS,TERBIT    ;IF A CALL TO "TERPRI" YOU ARE THROUGH
+       JRST    RFALSE
+
+       MOVE    A,(AB)  ;FIRST WORD OF ARGUMENT GOES INTO REG A
+       MOVE    B,1(AB) ;SECOND WORD INTO REG B
+       PUSHJ   P,IPRINT        ;CALL INTERNAL ROUTINE TO PRINT IT
+
+       MOVEI   A,SPACE
+       TLNE    FLAGS,SPCBIT    ;SKIP (PRINT A TRAILING SPACE) IF SPCBIT IS ON
+       PUSHJ   P,PITYO
+
+       MOVE    A,(AB)  ;GET FIRST ARGUMENT TO RETURN AS PRINT'S VALUE
+       MOVE    B,1(AB)
+
+       POP     P,E     ;RESTORE REGISTERS C,D, AND E
+       POP     P,D
+       POP     P,C
+       POP     P,FLAGS ;RESTORE THE FLAGS REGISTER
+       JRST    FINIS
+
+
+
+
+
+
+RFALSE:        MOVSI   A,TFALSE
+       MOVEI   B,0
+       JRST    FINIS
+\fIPRINT:       PUSH    P,C     ;SAVE REGISTER C ON THE P-STACK
+       PUSH    P,FLAGS ;SAVE PREVIOUS FLAGS
+       PUSH    TP,A    ;SAVE ARGUMENT ON TP-STACK
+       PUSH    TP,B
+
+       INTGO           ;ALLOW INTERRUPTS HERE
+       HLRZ    A,-1(TP)        ;GET THE TYPE CODE OF THE ITEM
+
+       CAILE   A,NUMPRI        ;SKIP IF TYPE NOT OUTSIDE OF VALID RANGE
+       JRST    PUNK    ;JUMP TO ERROR ROUTINE IF CODE TOO GREAT
+       JRST    @PTBL(A)        ;USE IT AS INDEX TO TRANSFER TABLE TO PRINT ITEM
+
+DISTBL PTBL,PUNK,[[TATOM,PATOM],[TFORM,PFORM],[TSEG,PSEG],[TFIX,PFIX]
+[TFLOAT,PFLOAT],[TLIST,PLIST],[TVEC,PVEC],[TCHRS,PCHRS],[TCHSTR,PCHSTR]
+[TARGS,PARGS],[TFRAME,PFRAME],[TUVEC,PUVEC],[TDEFER,PDEFER]
+[TUNAS,PUNAS]]
+
+PUNK:  MOVE    C,TYPVEC+1(TVP) ;GET AOBJN-POINTER TO VECTOR OF TYPE ATOMS
+       HLRZ    B,-1(TP)        ;GET THE TYPE CODE INTO REG B
+       LSH     B,1     ;MULTIPLY BY TWO
+       HRL     B,B     ;DUPLICATE IT IN THE LEFT HALF
+       ADD     C,B     ;INCREMENT THE AOBJN-POINTER
+       JUMPGE  C,PRERR ;IF POSITIVE, INDEX > VECTOR SIZE
+
+       PUSHJ   P,RETIF1        ;START NEW LINE IF NO ROOM
+       MOVEI   A,"#    ;INDICATE TYPE-NAME FOLLOWS
+       PUSHJ   P,PITYO
+       MOVE    A,(C)   ;GET TYPE-ATOM
+       MOVE    B,1(C)
+       PUSHJ   P,IPRINT        ;PRINT ATOM-NAME
+       MOVE    B,(TP)  ;RESET THE REAL ARGUMENT POINTER
+       MOVEI   A,SPACE ;PRINT A SEPARATING SPACE
+       PUSHJ   P,PITYO
+
+       HRRZ    A,(C)   ;GET THE STORAGE-TYPE
+       JRST    @UKTBL(A)       ;USE DISPATCH TABLE ON STORAGE TYPE
+
+DISTBS UKTBL,POCTAL,[[S2WORD,PLIST],[S2NWORD,PVEC],[SNWORD,PUVEC]
+[SCHSTR,PCHSTR],[SFRAME,PFRAME],[SARGS,PARGS],[SPVP,PPVP]]
+
+
+
+\f;INTERNAL SUBROUTINE TO HANDLE CHARACTER OUTPUT
+;
+;PRINTER ITYO USED FOR FLATSIZE FAKE OUT
+PITYO: TLNN    FLAGS,FLTBIT
+       JRST    PITYO1
+       AOS     FLTSIZE+1       ;FLATSIZE DOESN'T PRINT
+                       ;INSTEAD IT COUNTS THE CHARACTERS THAT WOULD BE OUTPUT
+       SOSL    FLTMAX+1        ;UNLESS THE MAXIMUM IS EXCEEDED
+       POPJ    P,
+       MOVSI   A,TFALSE        ;IN WHICH CASE IT IMMEDIATELY GIVES UP AND RETURNS FALSE
+       MOVEI   B,0
+       JRST    FINIS
+
+PITYO1:        TLNN FLAGS,HSHBIT
+       JRST ITYO
+       EXCH A,HSHNUM+1
+       ROT A,-7
+       XOR A,HSHNUM+1
+       EXCH A,HSHNUM+1
+       SOSL HSHMAX+1
+       POPJ P,
+       MOVSI A,TFIX
+       MOVE B,HSHNUM+1
+       JRST FINIS
+
+\f;THE REAL THING
+;NOTE THAT THE FOLLOWING CODE HAS BUGS IF IT IS PRINTING OUT LONG
+;CHARACTER STRINGS
+; (NOTE THAT THE ABOVE COMMENT, IF TRUE, SHOULD NOT BE ADMITTED.)
+ITYO:  PUSH    P,FLAGS ;SAVE STUFF
+       PUSH    P,B
+       PUSH    P,C
+ITYOCH:        PUSH    P,A     ;SAVE OUTPUT CHARACTER
+
+       HRRZ    B,FLAGS ;GET CURRENT CHANNEL COUNT
+       ADDI    B,(TB)-1
+       MOVE    B,(B)   ;GET THE CHANNEL POINTER
+
+       CAIE    A,^L    ;SKIP IF THIS IS A FORM-FEED
+       JRST    NOTFF
+       SETZM   LINPOS(B)       ;ZERO THE LINE NUMBER
+       SETZM   CHRPOS(B)       ;       AND CHARACTER NUMBER.
+       XCT     IOINS(B)        ;FIRST DO A CARRIAGE RETURN-LINE FEED
+       MOVEI   A,^L
+       JRST    ITYXT
+
+NOTFF: CAIE    A,^M    ;SKIP IF IT IS A CARRIAGE RETURN
+       JRST    NOTCR
+       SETZM   CHRPOS(B)       ;ZERO THE CHARACTER POSITION
+       XCT     IOINS(B)        ;OUTPUT THE C-R
+       MOVEI   A,^J    ;FOLLOW WITTH A LINE-FEED
+       AOS     C,LINPOS(B)     ;ADD ONE TO THE LINE NUMBER
+       CAMG    C,PAGLN(B)      ;SKIP IF THIS TAKES US PAST PAGE END
+       JRST    ITYXT
+
+       SETZM   LINPOS(B)       ;ZERO THE LINE POSITION
+       XCT     IOINS(B)        ;OUTPUT THE LINE FEED
+       MOVEI   A,^L    ;GET A FORM FEED
+       JRST    ITYXT
+
+NOTCR: CAIN    A,^I    ;SKIP IF NOT TAB
+       JRST    TABCNT
+       CAIN    A,^J    ;SKIP IF NOT LINE FEED
+       JRST    ITYXT   ;ELSE, DON'T COUNT (JUST OUTPUT IT)
+       AOS     CHRPOS(B)       ;ADD TO CHARACTER NUMBER
+
+ITYXT: XCT     IOINS(B)        ;OUTPUT THE CHARACTER
+       POP     P,A     ;RESTORE THE ORIGINAL CHARACTER
+       SUBI    FLAGS,2 ;DECREMENT CHANNEL COUNT
+       TRNE    FLAGS,-1        ;ANY MORE CHANNELS ?
+       JRST    ITYOCH  ;IF SO GO OUTPUT TO THEM
+
+       POP     P,C     ;RESTORE REGS & RETURN
+       POP     P,B
+       POP     P,FLAGS
+       POPJ    P,
+
+TABCNT:        PUSH    P,D
+       MOVE    C,CHRPOS(B)
+       ADDI    C,8.    ;INCREMENT COUNT BY EIGHT (MOD EIGHT)
+       IDIVI   C,8.
+       IMULI   C,8.
+       MOVEM   C,CHRPOS(B)     ;REPLACE COUNT
+       POP     P,D
+       JRST    ITYXT
+
+\fRETIF1:       MOVEI   A,1
+
+RETIF: TLNE    FLAGS,FLTBIT
+       POPJ    P,      ;IF WE ARE IN FLATSIZE THEN ESCAPE
+       TLNE    FLAGS,HSHBIT    ;ALSO ESCAPE IF IN HASH
+       POPJ    P,
+       PUSH    P,FLAGS
+       PUSH    P,B
+RETCH: PUSH    P,A
+
+       HRRZ    B,FLAGS ;GET THE CURRENT CHANNEL COUNT
+       ADDI    B,(TB)-1        ;CORRECT PLACE ON STACK
+       MOVE    B,(B)   ;GET THE CHANNEL POINTER
+       ADD     A,CHRPOS(B)     ;ADD THE CHARACTER POSITION
+       CAMG    A,LINLN(B)      ;SKIP IF GREATER THAN LINE LENGTH
+       JRST    RETXT
+
+       MOVEI   A,^M    ;FORCE A CARRIAGE RETURN
+       SETZM   CHRPOS(B)
+       XCT     IOINS(B)
+       MOVEI   A,^J    ;AND FORCE A LINE FEED
+       XCT     IOINS(B)
+       AOS     A,LINPOS(B)
+       CAMG    A,PAGLN(B)      ;AT THE END OF THE PAGE ?
+       JRST    RETXT
+       MOVEI   A,^L    ;IF SO FORCE A FORM FEED
+       XCT     IOINS(B)
+       SETZM   LINPOS(B)
+
+RETXT: POP     P,A
+       SUBI    FLAGS,2 ;DECREMENT CHANNEL COUNT
+       TRNE    FLAGS,-1        ;ANY MORE CHANNELS ?
+       JRST    RETCH   ;IF SO GO CONSIDER THEM
+
+       POP     P,B
+       POP     P,FLAGS
+       POPJ    P,      ;RETURN
+
+PRETIF:        PUSH    P,A     ;SAVE CHAR
+       PUSHJ   P,RETIF1
+       POP     P,A
+       JRST    PITYO
+
+\f;THIS IS CODE TO HANDLE UNKNOWN DATA TYPES.
+;IT PRINTS "*XXXXXX*XXXXXXXXXXXX*", WHERE THE FIRST NUMBER IS THE
+;TYPE CODE IN OCTAL, THE SECOND IS THE VALUE FIELD IN OCTAL.
+PRERR: MOVEI   A,21.   ;CHECK FOR 21. SPACES LEFT ON PRINT LINE
+       PUSHJ   P,RETIF ;INSERT CARRIAGE RETURN IF NOT ENOUGH
+       MOVEI   A,"*    ;JUNK TO INDICATE ERROR PRINTOUT IN OCTAL
+       PUSHJ   P,PITYO ;TYPE IT
+
+       MOVE    E,[000300,,-2(TP)]      ;GET POINTER INDEXED OFF TP SO THAT
+                               ;TYPE CODE MAY BE OBTAINED FOR PRINTING.
+       MOVEI   D,6     ;# OF OCTAL DIGITS IN HALF WORD
+OCTLP1:        ILDB    A,E     ;GET NEXT 3-BIT BYTE OF TYPE CODE
+       IORI    A,60    ;OR-IN 60 FOR ASCII DIGIT
+       PUSHJ   P,PITYO ;PRINT IT
+       SOJG    D,OCTLP1        ;REPEAT FOR SIX CHARACTERS
+
+PRE01: MOVEI   A,"*    ;DELIMIT TYPE CODE FROM VALUE FIELD
+       PUSHJ   P,PITYO
+
+       HRLZI   E,(410300,,(TP))        ;BYTE POINTER TO SECOND WORD
+                               ;INDEXED OFF TP
+       MOVEI   D,12.   ;# OF OCTAL DIGITS IN A WORD
+OCTLP2:        LDB     A,E     ;GET 3 BITS
+       IORI    A,60    ;CONVERT TO ASCII
+       PUSHJ   P,PITYO ;PRINT IT
+       IBP     E       ;INCREMENT POINTER TO NEXT BYTE
+       SOJG    D,OCTLP2        ;REPEAT FOR 12. CHARS
+
+       MOVEI   A,"*    ;DELIMIT END OF ERROR TYPEOUT
+       PUSHJ   P,PITYO ;REPRINT IT
+
+       JRST    PNEXT   ;RESTORE REGS & POP UP ONE LEVEL TO CALLER
+
+POCTAL:        MOVEI   A,14.   ;RETURN TO NEW LINE IF 14. SPACES NOT LEFT
+       PUSHJ   P,RETIF
+       JRST    PRE01   ;PRINT VALUE AS "*XXXXXXXXXXXX*"
+
+\f;PRINT BINARY INTEGERS IN DECIMAL.
+;
+PFIX:  MOVEI   E,FIXB  ;GET ADDRESS OF FIXED POINT CONVERSION ROUTINE
+       MOVE    D,[4,,4]        ;PUT # WORDS RESERVED ON STACK INTO REG F
+       JRST    PNUMB   ;PRINT THE NUMBER
+
+;PRINT SINGLE-PRECISION FLOATING POINT NUMBERS IN DECIMAL.
+;
+PFLOAT:        MOVEI   E,FLOATB        ;ADDRESS OF FLOATING POINT CONVERSION ROUTINE
+       MOVE    D,[6,,6]        ;# WORDS TO GET FROM STACK
+
+PNUMB: HRLI    A,1(P)  ;LH(A) TO CONTAIN ADDRESS OF RETURN AREA ON STACK
+       HRR     A,TP    ;RH(A) TO CONTAIN ADDRESS OF DATA ITEM
+       HLRZ    B,A     ;SAVE RETURN AREA ADDRESS IN REG B
+       ADD     P,D     ;ADD # WORDS OF RETURN AREA TO BOTH HALVES OF SP
+       JUMPGE  P,PDLERR        ;PLUS OR ZERO STACK POINTER IS OVERFLOW
+       PUSHJ   P,(E)   ;CALL ROUTINE WHOSE ADDRESS IS IN REG E
+
+       MOVE    C,(B)   ;GET COUNT 0F # CHARS RETURNED
+       MOVE    A,C     ;MAKE SURE THAT # WILL FIT ON PRINT LINE
+       PUSHJ   P,RETIF ;START NEW LINE IF IT WON'T
+
+       HRLI    B,000700        ;MAKE REG B INTO BYTE POINTER TO FIRST CHAR LESS ONE
+PNUM01:        ILDB    A,B     ;GET NEXT BYTE
+       PUSHJ   P,PITYO ;PRINT IT
+       SOJG    C,PNUM01        ;DECREMENT CHAR COUNT: LOOP IF NON-ZERO
+
+       SUB     P,D     ;SUBTRACT # WORDS USED ON STACK FOR RETURN
+       JRST    PNEXT   ;STORE REGS & POP UP ONE LEVEL TO CALLER
+
+\f;PRINT SHORT (ONE WORD) CHARACTER STRINGS.
+;
+PCHRS: MOVEI   A,3     ;MAX # CHARS PLUS 2 (LESS ESCAPES)
+       TLNE    FLAGS,NOQBIT    ;SKIP IF QUOTES WILL BE USED
+       MOVEI   A,1     ;ELSE, JUST ONE CHARACTER POSSIBLE
+       PUSHJ   P,RETIF ;NEW LINE IF INSUFFICIENT SPACE
+       TLNE    FLAGS,NOQBIT    ;DON'T QUOTE IF IN PRINC MODE
+       JRST    PCASIS
+       MOVEI   A,"!    ;TYPE A EXCL
+       PUSHJ   P,PITYO
+       MOVEI   A,""            ;AND A DOUBLE QUOTE
+       PUSHJ   P,PITYO
+
+PCASIS:        LDB     A,[350700,,(TP)]        ;GET NEXT BYTE FROM WORD
+       TLNE    FLAGS,NOQBIT    ;SKIP IF WE ARE NOT IN PRINC MODE (NOQBIT=0)
+       JRST    PCPRNT  ;IF BIT IS ON, PRINT WITHOUT ESCAPING
+       CAIE    A,ESCHAR        ;SKIP IF NOT THE ESCAPE CHARACTER
+       JRST    PCPRNT  ;ESCAPE THE ESCAPE CHARACTER
+
+ESCPRT:        MOVEI   A,ESCHAR        ;TYPE THE ESCAPE CHARACTER
+       PUSHJ   P,PITYO 
+
+PCPRNT:        LDB     A,[350700,,(TP)]        ;GET THE CHARACTER AGAIN
+       PUSHJ   P,PITYO ;PRINT IT
+       JRST    PNEXT
+
+
+\f;PRINT DEFERED (INVISIBLE) ITEMS. (PRINTED AS THE THING POINTED TO)
+;
+PDEFER:        MOVE    A,(B)   ;GET FIRST WORD OF ITEM
+       MOVE    B,1(B)  ;GET SECOND
+       PUSHJ   P,IPRINT        ;PRINT IT
+       JRST    PNEXT   ;GO EXIT
+
+;PRINT ATOM NAMES.
+;
+PATOM: TLO     FLAGS,ATMBIT    ;INDICATE ATOM-NAME PRINT OUT
+       HRRZ    B,(TP)  ;GET ADDRESS OF ATOM
+       ADDI    B,2     ;POINT TO FIRST P-NAME WORD
+       HRLI    B,350700        ;MAKE INTO A BYTE POINTER
+       HLRE    A,(TP)  ;GET LENGTH
+       MOVMS   A       ;ABSOLUTE VALUE
+       ADDI    A,-1(B) ;POINT TO LAST WORD
+       HRLI    A,TCHSTR        ;CHANGE TYPE
+       PUSH    TP,A    ;PUT STRING ON STACK
+       PUSH    TP,B
+
+       MOVE    D,[AOS E]       ;GET COUNTING INSTRUCTION
+       SETZM   E       ;ZERO COUNT
+       PUSHJ   P,PCHRST        ;COUNT CHARACTERS & ESCAPES
+       MOVE    A,E     ;GET RETURNED COUNT
+       PUSHJ   P,RETIF ;DO A CARRIAGE RETURN IF NOT ENOUGH ROOM ON THIS LINE
+
+       MOVEM   B,(TP)  ;RESET BYTE POINTER
+       MOVE    D,[PUSHJ P,PITYO]       ;GET OUTPUT INSTRUCTION
+       PUSHJ   P,PCHRST        ;PRINT STRING
+
+       SUB     TP,[2,,2]       ;REMOVE CHARACTER STRING ITEM
+       JRST    PNEXT
+
+\f;PRINT LONG CHARACTER STRINGS.
+;
+PCHSTR:        TLZ     FLAGS,ATMBIT    ;WE ARE NOT USING ATOM-NAME TYPE ESCAPING
+
+       MOVE    D,[AOS E]       ;GET INSTRUCTION TO COUNT CHARACTERS
+       SETZM   E       ;ZERO COUNT
+       PUSHJ   P,PCHRST        ;GO THROUGH STRING, ESCAPING, ETC. AND COUNTING
+       MOVE    A,E     ;PUT COUNT RETURNED IN REG A
+       TLNN    FLAGS,NOQBIT    ;SKIP (NO QUOTES) IF IN PRINC (BIT ON)
+       ADDI    A,2     ;PLUS TWO FOR QUOTES
+       PUSHJ   P,RETIF ;START NEW LINE IF NO SPACE
+
+       TLNE    FLAGS,NOQBIT    ;SKIP (PRINT ") IF BIT IS OFF (NOT PRINC)
+       JRST    PCHS01  ;OTHERWISE, DON'T QUOTE
+       MOVEI   A,""    ;PRINT A DOUBLE QUOTE
+       PUSHJ   P,PITYO
+
+PCHS01:        MOVE    D,[PUSHJ P,PITYO]       ;OUTPUT INSTRUCTION
+       MOVEM   B,(TP)  ;RESET BYTE POINTER
+       PUSHJ   P,PCHRST        ;TYPE STRING
+
+       TLNE    FLAGS,NOQBIT    ;AGAIN, SKIP IF DOUBLE-QUOTING TO BE DONE
+       JRST    PNEXT   ;RESTORE REGS & POP UP ONE LEVEL TO CALLER
+       MOVEI   A,""    ;PRINT A DOUBLE QUOTE
+       PUSHJ   P,PITYO
+       JRST    PNEXT
+
+
+\f;INTERNAL ROUTINE USED TO COUNT OR OUTPUT CHARACTER STRINGS.
+;
+;THE APPROPRIATE ESCAPING CONVENTIONS ARE USED AS DETERMINED BY THE FLAG BITS.
+;
+PCHRST:        PUSH    P,A     ;SAVE REGS
+       PUSH    P,B
+       PUSH    P,C
+       LDB     A,(TP)  ;GET FIRST BYTE
+       SKIPA
+
+PCHR02:        ILDB    A,(TP)  ;GET THE NEXT CHARACTER
+       JUMPE   A,PCSOUT        ;ZERO BYTE TERMINATES
+       HRRZ    C,-1(TP)        ;GET ADDRESS OF DOPE WORD
+       HRRZ    B,(TP)  ;GET WORD ADDRESS OF LAST BYTE
+       CAIL    B,-1(C) ;SKIP IF IT IS AT LEAST TWO BEFORE DOPE WORD
+       JRST    PCSOUT  ;ELSE, STRING IS FINISHED
+
+       TLNE    FLAGS,NOQBIT    ;SKIP IF WE ARE NOT IN PRINC MODE (NOQBIT=0)
+       JRST    PCSPRT  ;IF BIT IS ON, PRINT WITHOUT ESCAPING
+       CAIN    A,ESCHAR        ;SKIP IF NOT THE ESCAPE CHARACTER
+       JRST    ESCPRN  ;ESCAPE THE ESCAPE CHARACTER
+       CAIN    A,""    ;SKIP IF NOT A DOUBLE QUOTE
+       JRST    ESCPRN  ;OTHERWISE, ESCAPE THE """
+       IDIVI   A,CHRWD ;CODE HERE FINDS CHARACTER TYPE
+       LDB     B,BYTPNT(B)     ; "
+       CAIG    B,NONSPC                ;SKIP IF ATOM-BREAKER
+       JRST    PCSPRT  ;OTHERWISE, PRINT IT
+       TLNN    FLAGS,ATMBIT    ;SKIP IF PRINTING AN ATOM-NAME (UNQUOTED)
+       JRST    PCSPRT  ;OTHERWISE, NO OTHER CHARS TO ESCAPE
+
+ESCPRN:        MOVEI   A,ESCHAR        ;TYPE THE ESCAPE CHARACTER
+       XCT     D       
+
+PCSPRT:        LDB     A,(TP)  ;GET THE CHARACTER AGAIN
+       XCT     D       ;PRINT IT
+       JRST    PCHR02  ;LOOP THROUGH STRING
+
+PCSOUT:        POP     P,C     ;RESTORE REGS & RETURN
+       POP     P,B
+       POP     P,A
+       POPJ    P,
+
+
+\f;PRINT AN ARGUMENT LIST
+;CHECK FOR TIME ERRORS
+
+PARGS: MOVEI   B,-1(TP)                ;POINT TO ARGS POINTER
+       PUSHJ   P,CHARGS                ;AND CHECK THEM
+       JRST    PVEC    ; CHEAT TEMPORARILY
+
+
+
+;PRINT A FRAME
+PFRAME:        MOVEI   B,-1(TP)                ;POINT TO FRAME POINTER
+       PUSHJ   P,CHFRM
+       HRRZ    B,(TP)          ;POINT TO FRAME ITSELF
+       HRRZ    B,FSAV(B)               ;GET POINTER TO SUBROUTINE
+       MOVE    B,@-1(B)                ;PICKUP ATOM
+       PUSH    TP,$TATOM
+       PUSH    TP,B            ;SAVE IT
+       MOVSI   A,TATOM
+       MOVE    B,MQUOTE -STACK-FRAME-FOR-
+       PUSHJ   P,IPRINT                ;PRINT IT
+       POP     TP,B
+       POP     TP,A
+       PUSHJ   P,IPRINT                ;PRINT FUNCTION NAME
+       JRST    PNEXT
+
+PPVP:  MOVE    B,MQUOTE -PROCESS-
+       MOVSI   A,TATOM
+       PUSHJ   P,IPRINT
+       MOVE    B,(TP)          ;GET PVP
+       MOVE    A,PROCID(B)
+       MOVE    B,PROCID+1(B)   ;GET ID
+       PUSHJ   P,IPRINT
+       JRST    PNEXT
+\f;PRINT UNIFORM VECTORS.
+;
+PUVEC: MOVEI   A,"!    ;TYPE AN ! AND OPEN SQUARE BRACKET
+       PUSHJ   P,PRETIF
+       MOVEI   A,"[
+       PUSHJ   P,PRETIF
+
+       MOVE    C,(TP)  ;GET AOBJN POINTER TO VECTOR
+       TLNN    C,777777        ;SKIP ONLY IF COUNT IS NOT ZERO
+       JRST    NULVEC  ;ELSE, VECTOR IS EMPTY
+
+       HLRE    A,C     ;GET NEG COUNT
+       MOVEI   D,(C)   ;COPY POINTER
+       SUB     D,A     ;POINT TO DOPE WORD
+       HLLZ    A,(D)   ;GET TYPE
+       PUSH    P,A     ;AND SAVE IT
+
+PUVE02:        MOVE    A,(P)   ;PUT TYPE CODE IN REG A
+       MOVE    B,(C)   ;PUT DATUM INTO REG B
+       PUSHJ   P,IPRINT        ;TYPE IT
+
+       MOVE    C,(TP)  ;GET AOBJN POINTER
+       AOBJP   C,NULVE1        ;JUMP IF COUNT IS ZERO
+       MOVEM   C,(TP)  ;PUT POINTER BACK ONTO STACK
+
+       MOVEI   A,SPACE ;TYPE A BLANK
+       PUSHJ   P,PITYO
+       JRST    PUVE02  ;LOOP THROUGH VECTOR
+
+NULVE1:        SUB     P,[1,,1]        ;REMOVE STACK CRAP
+NULVEC:        MOVEI   A,"!    ;TYPE CLOSE BRACKET
+       PUSHJ   P,PRETIF
+       MOVEI   A,"]
+       PUSHJ   P,PRETIF
+       JRST    PNEXT
+
+\f;PRINT A GENERALIZED VECTOR.
+;
+PVEC:  PUSHJ   P,RETIF1        ;NEW LINE IF NO ROOM FOR [
+       MOVEI   A,"[    ;PRINT A LEFT-BRACKET
+       PUSHJ   P,PITYO
+
+       MOVE    C,(TP)  ;GET AOBJN POINTER TO VECTOR
+       TLNN    C,777777        ;SKIP IF POINTER-COUNT IS NON-ZERO
+       JRST    PVCEND  ;ELSE, FINISHED WITH VECTOR
+PVCR01:        MOVE    A,(C)   ;PUT FIRST WORD OF NEXT ELEMENT INTO REG A
+       MOVE    B,1(C)  ;SECOND WORD OF LIST INTO REG B
+       PUSHJ   P,IPRINT        ;PRINT THAT ELEMENT
+
+       MOVE    C,(TP)  ;GET AOBJN POINTER FROM TP-STACK
+       AOBJP   C,PDLERR        ;POSITIVE HERE SERIOUS ERROR! (THOUGH NOT PDL)
+       AOBJN   C,.+2   ;SKIP AND CONTINUE LOOP IF COUNT NOT ZERO
+       JRST    PVCEND  ;ELSE, FINISHED WITH VECTOR
+       MOVEM   C,(TP)  ;PUT INCREMENTED POINTER BACK ON TP-STACK
+
+       MOVEI   A,"     ;PRINT A SPACE
+       PUSHJ   P,PITYO
+       JRST    PVCR01  ;CONTINUE LOOPING THROUGH OBJECTS ON VECTOR
+
+PVCEND:        PUSHJ   P,RETIF1        ;NEW LINE IF NO ROOM FOR ]
+       MOVEI   A,"]    ;PRINT A RIGHT-BRACKET
+       PUSHJ   P,PITYO
+       JRST    PNEXT
+
+;PRINT A LIST.
+;
+PLIST: PUSHJ   P,RETIF1        ;NEW LINE IF NO SPACE LEFT FOR "("
+       MOVEI   A,"(    ;TYPE AN OPEN PAREN
+       PUSHJ   P,PITYO
+       PUSHJ   P,LSTPRT        ;PRINT THE INSIDES
+       PUSHJ   P,RETIF1        ;NEW LINE IF NO ROOM FOR THE CLOSE PAREN
+       MOVEI   A,")    ;TYPE A CLOSE PAREN
+       PUSHJ   P,PITYO
+       JRST    PNEXT
+
+
+
+;PRINT AN UNASSIGNED
+
+PUNAS: PUSHJ   P,RETIF1
+       MOVEI   A,"?
+       PUSHJ   P,PITYO
+       JRST    PLIST\fPSEG:     TLOA    FLAGS,SEGBIT    ;PRINT A SEGMENT (& SKIP)
+
+PFORM: TLZ     FLAGS,SEGBIT    ;PRINT AN ELEMENT
+
+PLMNT3:        MOVE    C,(TP)
+       JUMPE   C,PLMNT1        ;IF THE CALL IS EMPTY GO AWAY
+       MOVE    B,1(C)
+       MOVEI   D,0
+       CAMN    B,MQUOTE LVAL
+       MOVEI   D,".
+       CAMN    B,MQUOTE GVAL
+       MOVEI   D,",
+       CAMN    B,MQUOTE QUOTE
+       MOVEI   D,"'
+       CAMN    B,MQUOTE GIVEN
+       MOVEI   D,"?
+       CAMN    B,MQUOTE ALTER
+       MOVEI   D,"_
+       JUMPE   D,PLMNT1                ;NEITHER, LEAVE
+
+;ITS A SPECIAL HACK
+       HRRZ    C,(C)
+       JUMPE   C,PLMNT1        ;NIL BODY?
+
+;ITS VALUE OF AN ATOM
+       HLLZ    A,(C)
+       MOVE    B,1(C)
+       HRRZ    C,(C)
+       JUMPN   C,PLMNT1        ;IF TERE ARE EXTRA ARGS GO AWAY
+
+       PUSH    P,D             ;PUSH THE CHAR
+       PUSH    TP,A
+       PUSH    TP,B
+       TLNN    FLAGS,SEGBIT    ;SKIP (CONTINUE) IF THIS IS A SEGMENT
+       JRST    PLMNT4  ;ELSE DON'T PRINT THE "."
+
+;ITS A SEGMENT CALL
+       PUSHJ   P,RETIF1
+       MOVEI   A,"!
+       PUSHJ   P,PITYO
+
+PLMNT4:        PUSHJ   P,RETIF1
+       POP     P,A             ;RESTORE CHAR
+       PUSHJ   P,PITYO
+       POP     TP,B
+       POP     TP,A
+       PUSHJ   P,IPRINT
+       JRST    PNEXT
+
+\f
+PLMNT1:        TLNN    FLAGS,SEGBIT    ;SKIP IF THIS IS A SEGMENT
+       JRST    PLMNT5  ;ELSE DON'T TYPE THE "!"
+
+;ITS A SEGMENT CALL
+       PUSHJ   P,RETIF1
+       MOVEI   A,"!
+       PUSHJ   P,PITYO
+\rPLMNT5:       PUSHJ   P,RETIF1        
+       MOVEI   A,"<
+       PUSHJ   P,PITYO
+       PUSHJ   P,LSTPRT
+       MOVEI   A,"!
+       TLNE    FLAGS,SEGBIT    ;SKIP IF NOT SEGEMNT
+       PUSHJ   P,PRETIF
+       MOVEI   A,">
+       PUSHJ   P,PRETIF
+       JRST    PNEXT
+
+\fLSTPRT:       INTGO   ;WATCH  OUT FOR GARBAGE COLLECTION!
+       SKIPN   C,(TP)
+       POPJ    P,
+       HLLZ    A,(C)   ;GET NEXT ELEMENT
+       MOVE    B,1(C)
+       HRRZ    C,(C)   ;CHOP THE LIST
+       JUMPN   C,PLIST1
+       PUSHJ   P,IPRINT        ;PRINT THE LAST ELEMENT
+       POPJ    P,
+
+PLIST1:        MOVEM   C,(TP)
+       PUSHJ   P, IPRINT       ;PRINT THE NEXT ELEMENT
+       PUSHJ   P,RETIF1
+       MOVEI   A," 
+       PUSHJ   P,PITYO ;PRINT THE SPACE AFTER THE NEXT ELEMENT
+       JRST    LSTPRT  ;REPEAT
+
+PNEXT: POP     P,FLAGS ;RESTORE PREVIOUS FLAG BITS
+       SUB     TP,[2,,2]       ;REMOVE INPUT ELEMENT FROM TP-STACK
+       POP     P,C     ;RESTORE REG C
+       POPJ    P,
+
+PDLERR:        .VALUE  0       ;P-STACK OVERFLOW, VERY SERIOUS, MUDDLE DIES!
+
+CHNERR:        PUSH    TP,$TATOM
+       PUSH    TP,MQUOTE BAD-CHANNEL
+       JRST    CALER1
+
+ARGERR:        PUSH    TP,$TATOM       ;TYPE WRONG # ARGUMENTS
+       PUSH    TP,MQUOTE WRONG-NUMBER-OF-ARGUMENTS
+       JRST    CALER1
+
+END
+\f\f\ 3\f
\ No newline at end of file