; Copyright (c) 1993-1999 by Richard Kelsey. See file COPYING. ; Pretty-printing the node tree ; Sample output: ; 34 (F_12 (C_11 UNIT_0) ; (SET-CONTENTS 1 C_11 UNIT_0 UNIT '0 ^F_14)) ; ; 35 (F_14 (C_13 N_1) ; 36 (LET* (((LOOP_73) (CONS CELL '0)) ; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34)) ; 38 ((V_77) (CONTENTS LOOP_73 CELL '0))) ; (V_77 1 C_13 N_1 '1))) ; ; 39 (F_34 (C_33 I_9 R_7) ; 40 (LET* (((V_61) (CONTENTS UNIT_0 UNIT '3)) ; 41 ((V_63) (V_61 I_9 '0))) ; (TRUE? 2 ^C_58 ^C_41 V_63))) ; ; 42 (C_58 () ; (C_33 0 R_7)) ; ; 43 (C_41 () ; 44 (LET* (((V_46) (CONTENTS UNIT_0 UNIT '2)) ; 45 ((V_56) (V_46 I_9 R_7)) ; 46 ((V_44) (CONTENTS UNIT_0 UNIT '1)) ; 47 ((V_54) (V_44 I_9 '1)) ; 48 ((V_52) (CONTENTS LOOP_73 CELL '0))) ; (V_52 1 C_33 V_54 V_56))) ; What it means: ; Variables `_' V_61 ; Primops `' CONTENTS ; Lambdas `^' ^F_34 ; Literals `'' '0 ; 35 (F_14 (C_13 N_1) ; This is the header for a lambda node. `35' is the object hash of the node. ; `F_14' is the LAMBDA-NAME and LAMBDA-ID, `(C_13 N_1)' is the variable list. The ; start of this line (not counting the object hash) is indented one column ; more than the start of the lexically superior lambda. ; 36 (LET* (((LOOP_73) (CONS CELL '0)) ; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34)) ; 38 ((V_77) (CONTENTS LOOP_73 CELL '0))) ; (V_77 1 C_13 N_1 '1))) ; This is the body of the lambda. It is a block consisting of three simple ; calls and then a tail recursive call. The simple calls are in the form ; of a LET* that allows multiple value returns. The actual body of the ; lambda is the call `(CONS CELL '0)'. The continuation to this call is ; a lambda node `(LAMBDA (LOOP_73) (SET-CONTENTS ...))'. `36' is the ; object hash of this continuation lambda. ; After the block any lambdas in the block are printed. This lambda is ; followed by `F_34'. ; (PP-CPS node . port) ;--------------------------------------------------------------------------- ; Print CPS node tree in linear form. Port defaults to the current output port. ; This just dispatches on the type of NODE. (define (pp-cps node . port) (let* ((port (if (null? port) (current-output-port) (car port))) (port (if (current-column port) port (make-tracking-output-port port)))) (set! *rereadable?* #f) (cond ((lambda-node? node) (pp-cps-lambda node 4 port)) ((call-node? node) (write-non-simple-call node port)) (else (write-node-value node port))) (newline port) ((structure-ref i/o force-output) port))) (define (rereadable-pp-cps node port) (set! *rereadable?* #t) (pp-cps-lambda node 4 port) (values)) (define (indent port count) (let ((count (cond ((<= (current-column port) count) (- count (current-column port))) (else (newline port) count)))) (do ((count count (- count 1))) ((>= 0 count)) (writec port #\space)))) (define *rereadable?* #f) (define *next-pp-id* 0) (define (reset-pp-cps) (set! *next-pp-id* 0)) (define (next-pp-id) (let ((id *next-pp-id*)) (set! *next-pp-id* (+ *next-pp-id* 1)) id)) ; Print a lambda node by printing its identifiers, then its call, and finally ; any other lambdas that it includes. (define (pp-cps-lambda node indent-to port) (format port "~&~%") (cond ((not *rereadable?*) (node-hash node) (format port "~D" (lambda-id node)))) (indent port indent-to) (write-lambda-header node port) (let ((internal (pp-cps-body (lambda-body node) indent-to port))) (writec port #\)) (for-each (lambda (n) (pp-cps-lambda n (+ indent-to 1) port)) internal))) (define (write-lambda-header node port) (writec port '#\() (writec port (case (lambda-type node) ((proc known-proc) #\P) ((cont) #\C) ((jump) #\J) ((escape) #\E))) (writec port #\space) (print-lambda-name node port) (writec port #\space) (write-lambda-vars node port)) (define (write-lambda-vars node port) (let ((vars (lambda-variables node))) (cond ((not (null? vars)) (writec port '#\() (print-variable-name (car vars) port) (do ((v (cdr vars) (cdr v))) ((null? v)) (writec port '#\space) (print-variable-name (car v) port)) (writec port '#\))) (else (format port "()"))))) ; Print the body of a lambda node. A simple call is one that has exactly ; one exit. They and calls to lambda nodes are printed as a LET*. (define (pp-cps-body call indent-to port) (newline port) (cond ((or (simple-call? call) (let-call? call)) (write-let* call indent-to port)) (else (indent port (+ '2 indent-to)) (write-non-simple-call call port)))) ; Write out a series of calls as a LET*. The LET* ends when a call is reached ; that is neither a simple call or a call to a lambda. (define (write-let* call indent-to port) (cond ((not *rereadable?*) (node-hash (call-arg call 0)) (format port "~D" (lambda-id (call-arg call '0))))) (indent port (+ '2 indent-to)) (writec port '#\() (format port "LET* ") (writec port '#\() (let loop ((call (next-call call)) (ns (write-simple-call call indent-to port))) (cond ((or (simple-call? call) (let-call? call)) (newline port) (cond ((not *rereadable?*) (format port "~D" (lambda-id (call-arg call '0))) (node-hash (call-arg call 0)))) (indent port (+ '9 indent-to)) (loop (next-call call) (append (write-simple-call call indent-to port) ns))) (else (writec port '#\)) (newline port) (indent port (+ '4 indent-to)) (let ((ns (append (write-non-simple-call call port) ns))) (writec port '#\)) ns))))) (define (simple-call? call) (and (= '1 (call-exits call)) (not (lambda-block (call-arg call 0))))) (define (let-call? call) (calls-this-primop? call 'let)) ; Get the call that follows CALL in a LET*. (define (next-call call) (lambda-body (call-arg call '0))) ; Write out one line of a LET*. (define (write-simple-call call indent-to port) (if (let-call? call) (write-let-call call indent-to port) (really-write-simple-call call indent-to port))) ; Write the variables bound by the continuation and then the primop and ; non-continuation arguments of the call. (define (really-write-simple-call call indent-to port) (writec port '#\() (write-lambda-vars (call-arg call '0) port) (indent port (+ indent-to '21)) (writec port '#\() (format port "~S" (primop-id (call-primop call))) (write-call-args call '1 port) (writec port '#\)) (find-lambda-nodes call 1)) ; Write the variables of the lambda and then the values of the arguments. (define (write-let-call call indent-to port) (writec port '#\() (write-lambda-vars (call-arg call '0) port) (cond ((= '1 (vector-length (call-args call))) (writec port '#\)) '()) (else (writec port #\*) (indent port (+ indent-to '21)) (write-node-value (call-arg call '1) port) (write-call-args call '2 port) (find-lambda-nodes call 1)))) (define (find-lambda-nodes call start) (reverse (let label ((call call) (start start) (ls '())) (do ((i start (+ i 1)) (ls ls (let ((arg (call-arg call i))) (cond ((call-node? arg) (label arg 0 ls)) ((lambda-node? arg) (cons arg ls)) (else ls))))) ((>= i (call-arg-count call)) ls))))) ; Write out a call that ends a LET* block. (define (write-non-simple-call call port) (writec port '#\() (format port "~A ~D" (primop-id (call-primop call)) (call-exits call)) (write-call-args call '0 port) (find-lambda-nodes call 0)) ; Write out the arguments of CALL starting with START. (define (write-call-args call start port) (let* ((vec (call-args call)) (len (vector-length vec))) (do ((i start (+ i '1))) ((>= i len)) (writec port '#\space) (write-node-value (vector-ref vec i) port)) (writec port '#\)))) ; Print out a literal value. (define (cps-print-literal value port) (format port "'~S" value)) ; Dispatch on the type of NODE to get the appropriate printing method. (define (write-node-value node port) (cond ((not (node? node)) (format port "{not a node}")) ((lambda-node? node) (writec port '#\^) (print-lambda-name node port)) ((call-node? node) (format port "(~S" (primop-id (call-primop node))) (write-call-args node '0 port)) ((literal-node? node) (cps-print-literal (literal-value node) port)) ((reference-node? node) (print-variable-name (reference-variable node) port)) (else (bug "WRITE-NODE-VALUE got funny node ~S" node)))) ; Printing variables and lambda nodes ; #T if variables are supposed to print as the name of the register containing ; them instead of their name. (define *pp-register-names?* '#f) ; A whole bunch of different entry points for printing variables in slightly ; different ways. (define (print-variable-name var port) (cond ((not var) (format port "#f")) ; ((and *pp-register-names?* ; (reg? (variable-register var))) ; (format port "~S" (reg-name (variable-register var)))) (else (let ((id (cond ((not *rereadable?*) (variable-id var)) ((variable-flag var) => identity) (else (let ((id (next-pp-id))) (set-variable-flag! var id) id))))) (format port "~S_~S" (variable-name var) id))))) ; Same as the above without the check for a register. (define (print-variable-plain-name var port) (cond ((not var) (format port "#f")) (else (format port "~S_~D" (variable-name var) (variable-id var))))) ; Return the name as a string. (define (variable-print-name var) (print-variable-name var '#f)) ; Return the name as a symbol. (define (variable-unique-name var) (string->symbol (variable-print-name var))) ; Printing lambda-nodes as variables (define (print-lambda-name lnode port) (let ((id (cond ((not *rereadable?*) (lambda-id lnode)) ((node-flag lnode) => identity) (else (let ((id (next-pp-id))) (set-node-flag! lnode id) id))))) (format port "~S_~D" (lambda-name lnode) id))) (define (lambda-print-name lnode) (print-lambda-name lnode '#f)) (define (lambda-unique-name lnode) (string->symbol (lambda-print-name lnode)))