pp-cps.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
  2. ;;;
  3. ;;; Port Author: Andrew Whatson
  4. ;;;
  5. ;;; Original Authors: Richard Kelsey, Mike Sperber
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/node/pp-cps.scm
  8. ;;;
  9. ;;; Pretty-printing the node tree
  10. ;;;
  11. ;;; Sample output:
  12. ;;;
  13. ;;; 34 (F_12 (C_11 UNIT_0)
  14. ;;; (SET-CONTENTS 1 C_11 UNIT_0 UNIT '0 ^F_14))
  15. ;;;
  16. ;;; 35 (F_14 (C_13 N_1)
  17. ;;; 36 (LET* (((LOOP_73) (CONS CELL '0))
  18. ;;; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34))
  19. ;;; 38 ((V_77) (CONTENTS LOOP_73 CELL '0)))
  20. ;;; (V_77 1 C_13 N_1 '1)))
  21. ;;;
  22. ;;; 39 (F_34 (C_33 I_9 R_7)
  23. ;;; 40 (LET* (((V_61) (CONTENTS UNIT_0 UNIT '3))
  24. ;;; 41 ((V_63) (V_61 I_9 '0)))
  25. ;;; (TRUE? 2 ^C_58 ^C_41 V_63)))
  26. ;;;
  27. ;;; 42 (C_58 ()
  28. ;;; (C_33 0 R_7))
  29. ;;;
  30. ;;; 43 (C_41 ()
  31. ;;; 44 (LET* (((V_46) (CONTENTS UNIT_0 UNIT '2))
  32. ;;; 45 ((V_56) (V_46 I_9 R_7))
  33. ;;; 46 ((V_44) (CONTENTS UNIT_0 UNIT '1))
  34. ;;; 47 ((V_54) (V_44 I_9 '1))
  35. ;;; 48 ((V_52) (CONTENTS LOOP_73 CELL '0)))
  36. ;;; (V_52 1 C_33 V_54 V_56)))
  37. ;;;
  38. ;;; What it means:
  39. ;;;
  40. ;;; Variables `<name>_<id>' V_61
  41. ;;; Primops `<primop name>' CONTENTS
  42. ;;; Lambdas `^<self variable>' ^F_34
  43. ;;; Literals `'<value>' '0
  44. ;;;
  45. ;;; 35 (F_14 (C_13 N_1)
  46. ;;; This is the header for a lambda node. `35' is the object hash of the node.
  47. ;;; `F_14' is the LAMBDA-NAME and LAMBDA-ID, `(C_13 N_1)' is the variable list. The
  48. ;;; start of this line (not counting the object hash) is indented one column
  49. ;;; more than the start of the lexically superior lambda.
  50. ;;;
  51. ;;; 36 (LET* (((LOOP_73) (CONS CELL '0))
  52. ;;; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34))
  53. ;;; 38 ((V_77) (CONTENTS LOOP_73 CELL '0)))
  54. ;;; (V_77 1 C_13 N_1 '1)))
  55. ;;; This is the body of the lambda. It is a block consisting of three simple
  56. ;;; calls and then a tail recursive call. The simple calls are in the form
  57. ;;; of a LET* that allows multiple value returns. The actual body of the
  58. ;;; lambda is the call `(CONS CELL '0)'. The continuation to this call is
  59. ;;; a lambda node `(LAMBDA (LOOP_73) (SET-CONTENTS ...))'. `36' is the
  60. ;;; object hash of this continuation lambda.
  61. ;;; After the block any lambdas in the block are printed. This lambda is
  62. ;;; followed by `F_34'.
  63. ;;;
  64. ;;; (PP-CPS node . port)
  65. ;;;---------------------------------------------------------------------------
  66. ;;; Print CPS node tree in linear form. Port defaults to the current output port.
  67. ;;; This just dispatches on the type of NODE.
  68. (define-module (ps-compiler node pp-cps)
  69. #:use-module (ice-9 format)
  70. #:use-module (prescheme scheme48)
  71. #:use-module (ps-compiler node node)
  72. #:use-module (ps-compiler node node-util)
  73. #:use-module (ps-compiler node primop)
  74. #:use-module (ps-compiler node variable)
  75. #:use-module (ps-compiler util util)
  76. #:export (pp-cps))
  77. (define (pp-cps node . port)
  78. (let* ((port (if (null? port) (current-output-port) (car port)))
  79. (port (if (current-column port)
  80. port
  81. (make-tracking-output-port port))))
  82. (set! *rereadable?* #f)
  83. (cond ((lambda-node? node)
  84. (pp-cps-lambda node 4 port))
  85. ((call-node? node)
  86. (write-non-simple-call node port))
  87. (else
  88. (write-node-value node port)))
  89. (newline port)
  90. (force-output port)))
  91. (define (rereadable-pp-cps node port)
  92. (set! *rereadable?* #t)
  93. (pp-cps-lambda node 4 port)
  94. (values))
  95. (define (indent port count)
  96. (let ((count (cond ((<= (current-column port) count)
  97. (- count (current-column port)))
  98. (else
  99. (newline port)
  100. count))))
  101. (do ((count count (- count 1)))
  102. ((>= 0 count))
  103. (writec port #\space))))
  104. (define *rereadable?* #f)
  105. (define *next-pp-id* 0)
  106. (define (reset-pp-cps)
  107. (set! *next-pp-id* 0))
  108. (define (next-pp-id)
  109. (let ((id *next-pp-id*))
  110. (set! *next-pp-id* (+ *next-pp-id* 1))
  111. id))
  112. ;; Print a lambda node by printing its identifiers, then its call, and finally
  113. ;; any other lambdas that it includes.
  114. (define (pp-cps-lambda node indent-to port)
  115. (format port "~&~%")
  116. (cond ((not *rereadable?*)
  117. (node-hash node)
  118. (format port "~D" (lambda-id node))))
  119. (indent port indent-to)
  120. (write-lambda-header node port)
  121. (let ((internal (pp-cps-body (lambda-body node) indent-to port)))
  122. (writec port #\))
  123. (for-each (lambda (n)
  124. (pp-cps-lambda n (+ indent-to 1) port))
  125. internal)))
  126. (define (write-lambda-header node port)
  127. (writec port '#\()
  128. (writec port (case (lambda-type node)
  129. ((proc known-proc) #\P)
  130. ((cont) #\C)
  131. ((jump) #\J)
  132. ((escape) #\E)))
  133. (writec port #\space)
  134. (print-lambda-name node port)
  135. (writec port #\space)
  136. (write-lambda-vars node port))
  137. (define (write-lambda-vars node port)
  138. (let ((vars (lambda-variables node)))
  139. (cond ((not (null? vars))
  140. (writec port '#\()
  141. (print-variable-name (car vars) port)
  142. (do ((v (cdr vars) (cdr v)))
  143. ((null? v))
  144. (writec port '#\space)
  145. (print-variable-name (car v) port))
  146. (writec port '#\)))
  147. (else
  148. (format port "()")))))
  149. ;; Print the body of a lambda node. A simple call is one that has exactly
  150. ;; one exit. They and calls to lambda nodes are printed as a LET*.
  151. (define (pp-cps-body call indent-to port)
  152. (newline port)
  153. (cond ((or (simple-call? call)
  154. (let-call? call))
  155. (write-let* call indent-to port))
  156. (else
  157. (indent port (+ '2 indent-to))
  158. (write-non-simple-call call port))))
  159. ;; Write out a series of calls as a LET*. The LET* ends when a call is reached
  160. ;; that is neither a simple call or a call to a lambda.
  161. (define (write-let* call indent-to port)
  162. (cond ((not *rereadable?*)
  163. (node-hash (call-arg call 0))
  164. (format port "~D" (lambda-id (call-arg call '0)))))
  165. (indent port (+ '2 indent-to))
  166. (writec port '#\()
  167. (format port "LET* ")
  168. (writec port '#\()
  169. (let loop ((call (next-call call))
  170. (ns (write-simple-call call indent-to port)))
  171. (cond ((or (simple-call? call)
  172. (let-call? call))
  173. (newline port)
  174. (cond ((not *rereadable?*)
  175. (format port "~D" (lambda-id (call-arg call '0)))
  176. (node-hash (call-arg call 0))))
  177. (indent port (+ '9 indent-to))
  178. (loop (next-call call)
  179. (append (write-simple-call call indent-to port) ns)))
  180. (else
  181. (writec port '#\))
  182. (newline port)
  183. (indent port (+ '4 indent-to))
  184. (let ((ns (append (write-non-simple-call call port) ns)))
  185. (writec port '#\))
  186. ns)))))
  187. (define (simple-call? call)
  188. (= '1 (call-exits call)))
  189. (define (let-call? call)
  190. (calls-this-primop? call 'let))
  191. ;; Get the call that follows CALL in a LET*.
  192. (define (next-call call)
  193. (lambda-body (call-arg call '0)))
  194. ;; Write out one line of a LET*.
  195. (define (write-simple-call call indent-to port)
  196. (if (let-call? call)
  197. (write-let-call call indent-to port)
  198. (really-write-simple-call call indent-to port)))
  199. ;; Write the variables bound by the continuation and then the primop and
  200. ;; non-continuation arguments of the call.
  201. (define (really-write-simple-call call indent-to port)
  202. (writec port '#\()
  203. (write-lambda-vars (call-arg call '0) port)
  204. (indent port (+ indent-to '21))
  205. (writec port '#\()
  206. (format port "~S" (primop-id (call-primop call)))
  207. (write-call-args call '1 port)
  208. (writec port '#\))
  209. (find-lambda-nodes call 1))
  210. ;; Write the variables of the lambda and then the values of the arguments.
  211. (define (write-let-call call indent-to port)
  212. (writec port '#\()
  213. (write-lambda-vars (call-arg call '0) port)
  214. (cond ((= '1 (vector-length (call-args call)))
  215. (writec port '#\))
  216. '())
  217. (else
  218. (writec port #\*)
  219. (indent port (+ indent-to '21))
  220. (write-node-value (call-arg call '1) port)
  221. (write-call-args call '2 port)
  222. (find-lambda-nodes call 1))))
  223. (define (find-lambda-nodes call start)
  224. (reverse (let label ((call call) (start start) (ls '()))
  225. (do ((i start (+ i 1))
  226. (ls ls (let ((arg (call-arg call i)))
  227. (cond ((call-node? arg)
  228. (label arg 0 ls))
  229. ((lambda-node? arg)
  230. (cons arg ls))
  231. (else ls)))))
  232. ((>= i (call-arg-count call))
  233. ls)))))
  234. ;; Write out a call that ends a LET* block.
  235. (define (write-non-simple-call call port)
  236. (writec port '#\()
  237. (format port "~A ~D" (primop-id (call-primop call)) (call-exits call))
  238. (write-call-args call '0 port)
  239. (find-lambda-nodes call 0))
  240. ;; Write out the arguments of CALL starting with START.
  241. (define (write-call-args call start port)
  242. (let* ((vec (call-args call))
  243. (len (vector-length vec)))
  244. (do ((i start (+ i '1)))
  245. ((>= i len))
  246. (writec port '#\space)
  247. (write-node-value (vector-ref vec i) port))
  248. (writec port '#\))))
  249. ;; Print out a literal value.
  250. (define (cps-print-literal value port)
  251. (format port "'~S" value))
  252. ;; Dispatch on the type of NODE to get the appropriate printing method.
  253. (define (write-node-value node port)
  254. (cond ((not (node? node))
  255. (format port "{not a node}"))
  256. ((lambda-node? node)
  257. (writec port '#\^)
  258. (print-lambda-name node port))
  259. ((call-node? node)
  260. (format port "(~S" (primop-id (call-primop node)))
  261. (write-call-args node '0 port))
  262. ((literal-node? node)
  263. (cps-print-literal (literal-value node) port))
  264. ((reference-node? node)
  265. (print-variable-name (reference-variable node) port))
  266. (else
  267. (bug "WRITE-NODE-VALUE got funny node ~S" node))))
  268. ;; Printing variables and lambda nodes
  269. ;; #T if variables are supposed to print as the name of the register containing
  270. ;; them instead of their name.
  271. (define *pp-register-names?* '#f)
  272. ;; A whole bunch of different entry points for printing variables in slightly
  273. ;; different ways.
  274. (define (print-variable-name var port)
  275. (cond ((not var)
  276. (format port "#f"))
  277. ;; ((and *pp-register-names?*
  278. ;; (reg? (variable-register var)))
  279. ;; (format port "~S" (reg-name (variable-register var))))
  280. (else
  281. (let ((id (cond ((not *rereadable?*)
  282. (variable-id var))
  283. ((variable-flag var)
  284. => identity)
  285. (else
  286. (let ((id (next-pp-id)))
  287. (set-variable-flag! var id)
  288. id)))))
  289. (format port "~S_~S" (variable-name var) id)))))
  290. ;; Same as the above without the check for a register.
  291. (define (print-variable-plain-name var port)
  292. (cond ((not var)
  293. (format port "#f"))
  294. (else
  295. (format port "~S_~D" (variable-name var) (variable-id var)))))
  296. ;; Return the name as a string.
  297. (define (variable-print-name var)
  298. (print-variable-name var '#f))
  299. ;; Return the name as a symbol.
  300. (define (variable-unique-name var)
  301. (string->symbol (variable-print-name var)))
  302. ;; Printing lambda-nodes as variables
  303. (define (print-lambda-name lnode port)
  304. (let ((id (cond ((not *rereadable?*)
  305. (lambda-id lnode))
  306. ((node-flag lnode)
  307. => identity)
  308. (else
  309. (let ((id (next-pp-id)))
  310. (set-node-flag! lnode id)
  311. id)))))
  312. (format port "~S_~D" (lambda-name lnode) id)))
  313. (define (lambda-print-name lnode)
  314. (print-lambda-name lnode '#f))
  315. (define (lambda-unique-name lnode)
  316. (string->symbol (lambda-print-name lnode)))