File: pp-cps.scm

package info (click to toggle)
scheme48 1.8%2Bdfsg-1%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 14,984 kB
file content (355 lines) | stat: -rw-r--r-- 11,008 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
; Copyright (c) 1993-2008 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)))