356 lines
11 KiB
Scheme
356 lines
11 KiB
Scheme
; 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 `<name>_<id>' V_61
|
|
; Primops `<primop name>' CONTENTS
|
|
; Lambdas `^<self variable>' ^F_34
|
|
; Literals `'<value>' '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)))
|
|
|
|
|
|
|
|
|
|
|