c.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. ; Copyright (c) 1993-2008 by Richard Kelsey. See file COPYING.
  2. ; Translating the node tree into C
  3. (define (write-c-file init-name file header forms)
  4. (set! *c-variable-id* 0)
  5. (set! *type-uids* '())
  6. (set! *next-type-uid* 0)
  7. (let* ((real-out (open-output-file file))
  8. (out (make-tracking-output-port real-out)))
  9. (merge-forms forms)
  10. (check-hoisting forms)
  11. (format #t "Translating~%")
  12. (write-c-header header out)
  13. (write-function-prototypes forms out)
  14. (write-global-arg-variable-declarations forms out)
  15. (write-global-variable-declarations forms out)
  16. (newline out)
  17. (for-each (lambda (f)
  18. (case (form-type f)
  19. ((lambda)
  20. (compile-proc-to-c f out))
  21. ((alias constant integrate merged stob initialize unused)
  22. (values))
  23. (else
  24. (bug "unknown type of form ~S" f))))
  25. forms)
  26. (write-c-main init-name out forms)
  27. (newline out)
  28. (set! *type-uids* '())
  29. (close-output-port out)
  30. (close-output-port real-out)))
  31. (define (write-c-main init-name out forms)
  32. (set! *doing-tail-called-procedure?* #f)
  33. (set! *current-merged-procedure* #f)
  34. (cond ((any? (lambda (f)
  35. (or (eq? (form-type f) 'initialize)
  36. (eq? (form-type f) 'stob)
  37. (eq? (form-type f) 'alias)))
  38. forms)
  39. (write-c-main-header (if init-name init-name 'main) out)
  40. (for-each (lambda (f)
  41. (case (form-type f)
  42. ((initialize alias)
  43. (write-initialize (form-var f) (form-value f) out))
  44. ((stob)
  45. (write-stob (form-var f)
  46. (form-value-type f)
  47. (lambda-body (form-value f))
  48. out))))
  49. forms)
  50. (write-c-main-end out))))
  51. (define (write-c-header header out)
  52. (format out "#include <stdio.h>~%")
  53. (format out "#include <string.h>~%")
  54. (format out "#include <stdlib.h>~%")
  55. (format out "#include \"prescheme.h\"~%")
  56. (for-each (lambda (s)
  57. (display s out)
  58. (newline out))
  59. header)
  60. (for-each (lambda (rtype)
  61. (declare-record-type rtype out))
  62. (all-record-types))
  63. (newline out)
  64. (values))
  65. (define (declare-record-type rtype out)
  66. (format out "~%struct ")
  67. (write-c-identifier (record-type-name rtype) out)
  68. (format out " {~%")
  69. (for-each (lambda (field)
  70. (format out " ")
  71. (display-c-type (record-field-type field)
  72. (lambda (port)
  73. (write-c-identifier (record-field-name field)
  74. out))
  75. out)
  76. (format out ";~%"))
  77. (record-type-fields rtype))
  78. (format out "};"))
  79. ; Even when finished we need to keep the lambda around for help with
  80. ; calls to it.
  81. (define (compile-proc-to-c form out)
  82. (format #t " ~A~%" (form-c-name form))
  83. (let ((name (form-c-name form)))
  84. (proc->c name form (form-shadowed form) out #f)
  85. (for-each make-form-unused! (form-merged form))
  86. (erase (detach-body (lambda-body (form-value form))))
  87. (suspend-form-use! form)))
  88. (define (form-c-name form)
  89. (let* ((var (form-var form))
  90. (name (c-ify (variable-name var))))
  91. (if (generated-top-variable? var)
  92. (string-append "H" name (number->string (c-variable-id var)))
  93. name)))
  94. (define (no-value-node? node)
  95. (or (undefined-value-node? node)
  96. (and (reference-node? node)
  97. (let ((type (final-variable-type (reference-variable node))))
  98. (or (eq? type type/unit)
  99. (eq? type type/null))))))
  100. ;------------------------------------------------------------
  101. ; Initialization procedure at the end of the file (often called `main').
  102. ; Header for initialization code
  103. (define (write-c-main-header initname out)
  104. (format out "void~%")
  105. (write-c-identifier initname out)
  106. (format out "(void)~%{"))
  107. ; Write the end of the initialization code
  108. (define (write-c-main-end out)
  109. (format out "~&}"))
  110. (define (write-initialize var value out)
  111. (let ((wants (maybe-follow-uvar (variable-type var))))
  112. (receive (value has)
  113. (cond ((variable? value)
  114. (values value (final-variable-type value)))
  115. ((literal-node? value)
  116. (values (literal-value value) (literal-type value)))
  117. ((reference-node? value)
  118. (let ((var (reference-variable value)))
  119. (values var (final-variable-type var))))
  120. (else
  121. (error "unknown kind of initial value ~S" value)))
  122. (cond ((not (unspecific? value))
  123. (c-assign-to-variable var out 0)
  124. (if (not (type-eq? wants has))
  125. (write-c-coercion wants out))
  126. (cond ((input-port? value)
  127. (display "0" out))
  128. ((output-port? value)
  129. (display "1" out))
  130. ((variable? value)
  131. (c-variable value out))
  132. (else
  133. (c-literal-value value has out)))
  134. (writec out '#\;))))))
  135. (define (write-stob var type call out)
  136. (let ((value (literal-value (call-arg call 0)))
  137. (wants (final-variable-type var)))
  138. (c-assign-to-variable var out 0)
  139. (cond ((vector? value)
  140. (if (not (type-eq? type wants))
  141. (write-c-coercion wants out))
  142. (format out "malloc(~D * sizeof(" (vector-length value))
  143. (display-c-type (pointer-type-to type) #f out)
  144. (format out "));")
  145. (do ((i 0 (+ i 1)))
  146. ((>= i (vector-length value)))
  147. (let* ((elt (call-arg call (+ i 1)))
  148. (has (finalize-type
  149. (if (reference-node? elt)
  150. (variable-type (reference-variable elt))
  151. (literal-value-type (literal-value elt))))))
  152. (newline out)
  153. (c-variable var out)
  154. (format out "[~D] = " i)
  155. (if (not (type-eq? (pointer-type-to type) has))
  156. (write-c-coercion (pointer-type-to type) out))
  157. (c-value elt out)
  158. (write-char #\; out))))
  159. (else
  160. (error "don't know how to generate stob value ~S" value)))))
  161. ;------------------------------------------------------------
  162. ; Writing out a procedure.
  163. (define (proc->c name form rename-vars port maybe-merged-count)
  164. (let ((top (form-value form))
  165. (merged (form-merged form))
  166. (tail? (form-tail-called? form))
  167. (exported? (form-exported? form))
  168. (lambda-kids lambda-block)) ; filled in by the hoist code
  169. (let ((lambdas (filter (lambda (l)
  170. (not (proc-lambda? l)))
  171. (lambda-kids top))))
  172. (if maybe-merged-count
  173. (merged-proc->c name top lambdas merged maybe-merged-count port tail?)
  174. (real-proc->c name (form-var form) top lambdas
  175. merged rename-vars port tail? exported?))
  176. (values))))
  177. (define (write-merged-form form port)
  178. (format #t " ~A~%" (form-c-name form))
  179. ; (breakpoint "write-merged-form ~S" form)
  180. (proc->c (form-c-name form)
  181. form
  182. '()
  183. port
  184. (length (variable-refs (form-var form)))))
  185. ;------------------------------------------------------------
  186. ; 1. write the header
  187. ; 2. declare the local variables
  188. ; 3. write out the body
  189. ; 4. write out all of the label lambdas
  190. (define (real-proc->c id var top lambdas merged rename-vars port tail? exported?)
  191. (let ((vars (cdr (lambda-variables top)))
  192. (return-type (final-variable-type (car (lambda-variables top))))
  193. (all-lambdas (append lambdas (gather-merged-lambdas merged)))
  194. (merged-procs (gather-merged-procs merged)))
  195. (set! *doing-tail-called-procedure?* tail?)
  196. (set! *current-merged-procedure* #f)
  197. (receive (first rest)
  198. (parse-return-type return-type)
  199. (set! *extra-tail-call-args*
  200. (do ((i (length rest) (- i 1))
  201. (args '() (cons (format #f "TT~D" (- i 1)) args)))
  202. ((= i 0)
  203. args))))
  204. (set! *jumps-to-do* '())
  205. (write-procedure-header id return-type vars port tail? exported?)
  206. (write-char '#\{ port)
  207. (newline port)
  208. (for-each (lambda (v)
  209. (set-variable-flags! v (cons 'shadowed (variable-flags v))))
  210. rename-vars)
  211. (write-arg-variable-declarations all-lambdas merged port)
  212. (write-rename-variable-declarations rename-vars port)
  213. (write-merged-declarations merged port)
  214. (fixup-nasty-c-primops! (lambda-body top))
  215. (for-each (lambda (form)
  216. (write-merged-decls form port))
  217. merged)
  218. (clear-lambda-generated?-flags lambdas)
  219. (set! *local-vars* '())
  220. (let ((body (call-with-string-output-port
  221. (lambda (temp-port)
  222. (let ((temp-port (make-tracking-output-port temp-port)))
  223. (write-c-block (lambda-body top) temp-port 2)
  224. (write-jump-lambdas temp-port 0)
  225. (for-each (lambda (f)
  226. (write-merged-form f temp-port))
  227. (reverse merged)) ; makes for more readable output
  228. (newline temp-port)
  229. (force-output temp-port))))))
  230. (declare-local-variables port)
  231. (if tail?
  232. (write-global-argument-initializers (cdr (lambda-variables top))
  233. port 2))
  234. (format port "~% {")
  235. (display body port)
  236. (write-char '#\} port))
  237. (for-each (lambda (v)
  238. (set-variable-flags! v (delq! 'shadowed (variable-flags v))))
  239. rename-vars)
  240. (values)))
  241. ; These global variables should be replaced with fluids.
  242. (define *doing-tail-called-procedure?* #f)
  243. (define *current-merged-procedure* #f)
  244. (define *extra-tail-call-args* '())
  245. (define (gather-merged-lambdas merged)
  246. (let loop ((merged merged) (lambdas '()))
  247. (if (null? merged)
  248. lambdas
  249. (loop (append (form-merged (car merged)) (cdr merged))
  250. (append (form-lambdas (car merged)) lambdas)))))
  251. (define (gather-merged-procs merged)
  252. (let loop ((merged merged) (procs '()))
  253. (if (null? merged)
  254. procs
  255. (loop (append (form-merged (car merged)) (cdr merged))
  256. (cons (form-value (car merged)) procs)))))
  257. (define (write-merged-decls form port)
  258. (let ((top (form-value form))
  259. (merged (form-merged form)))
  260. (let ((vars (filter (lambda (var)
  261. (and (used? var)
  262. (not (eq? type/unit (final-variable-type var)))))
  263. (cdr (lambda-variables top)))))
  264. (write-variable-declarations vars port 2))
  265. (write-merged-declarations merged port)))
  266. (define (merged-proc->c name top lambdas merged return-count port tail?)
  267. (let ((vars (cdr (lambda-variables top)))
  268. (body (lambda-body top)))
  269. (set! *doing-tail-called-procedure?* tail?)
  270. (set! *current-merged-procedure* name)
  271. (write-merged-header name top port)
  272. (write-char '#\{ port)
  273. (clear-lambda-generated?-flags lambdas)
  274. (write-c-block body port 2)
  275. (write-jump-lambdas port 0)
  276. (if (not tail?)
  277. (write-merged-return name return-count port))
  278. (for-each (lambda (f)
  279. (write-merged-form f port))
  280. (reverse merged)) ; makes for more readable output
  281. (write-char '#\} port)
  282. (newline port)
  283. (values)))
  284. (define (write-merged-header name top port)
  285. (format port "~% ~A: {~%" name)
  286. (if (not (null? (cdr (lambda-variables top))))
  287. (write-merged-argument-initializers (cdr (lambda-variables top)) port 2)))
  288. ; We use `default:' for the last tag so that the C compiler will
  289. ; know that the code following the switch is unreachable (to avoid
  290. ; a spurious warning if this is the end of the procedure).
  291. (define (write-merged-return name return-count port)
  292. (format port "~% ~A_return:~% switch (~A_return_tag) {~%" name name)
  293. (do ((i 0 (+ i 1)))
  294. ((>= i (- return-count 1)))
  295. (format port " case ~S: goto ~A_return_~S;~%" i name i))
  296. (format port " default: goto ~A_return_~S;~%" name (- return-count 1))
  297. (format port " }"))
  298. (define (write-merged-declarations forms port)
  299. (for-each (lambda (f)
  300. (if (not (form-tail-called? f))
  301. (write-merged-declaration f port)))
  302. forms))
  303. (define (write-merged-declaration form port)
  304. (let ((name (form-c-name form))
  305. (types (lambda-return-types (form-value form))))
  306. (format port "~% int ~A_return_tag;" name)
  307. (do ((i 0 (+ i 1))
  308. (types types (cdr types)))
  309. ((null? types))
  310. (let ((type (car types)))
  311. (cond ((not (or (eq? type type/unit)
  312. (eq? type type/null)))
  313. (format port "~% ")
  314. (display-c-type type
  315. (lambda (port)
  316. (format port "~A~D_return_value" name i))
  317. port)
  318. (writec port #\;)))))))
  319. (define (lambda-return-types node)
  320. (let ((type (final-variable-type (car (lambda-variables node)))))
  321. (if (tuple-type? type)
  322. (tuple-type-types type)
  323. (list type))))
  324. (define (write-procedure-header id return-type vars port tail? exported?)
  325. (newline port)
  326. (if (not exported?)
  327. (display "static " port))
  328. (receive (first rest)
  329. (parse-return-type return-type)
  330. (display-c-type (if tail? type/integer first)
  331. (lambda (port)
  332. (if tail? (write-char #\T port))
  333. (display id port))
  334. port)
  335. (write-char '#\( port)
  336. (if (not tail?)
  337. (let ((args (append vars
  338. (do ((i 0 (+ i 1))
  339. (rest rest (cdr rest))
  340. (res '() (cons (cons i (car rest)) res)))
  341. ((null? rest)
  342. (reverse res))))))
  343. (if (null? args)
  344. (display "void" port)
  345. (write-variables args port))))
  346. (write-char '#\) port)
  347. (newline port)))
  348. ; Write the names of VARS out to the port. VARS may contain pairs of the
  349. ; form (<integer> . <type>) as well as variables.
  350. (define (write-variables vars port)
  351. (let ((do-one (lambda (var)
  352. (display-c-type (if (pair? var)
  353. (make-pointer-type (cdr var))
  354. (final-variable-type var))
  355. (lambda (port)
  356. (if (pair? var)
  357. (format port "TT~D" (car var))
  358. (c-variable var port)))
  359. port))))
  360. (cond ((null? vars)
  361. (values))
  362. ((null? (cdr vars))
  363. (do-one (car vars)))
  364. (else
  365. (do-one (car vars))
  366. (do ((vars (cdr vars) (cdr vars)))
  367. ((null? vars)
  368. (values))
  369. (write-char '#\, port)
  370. (write-char '#\space port)
  371. (do-one (car vars)))))))
  372. (define (write-rename-variable-declarations vars port)
  373. (for-each (lambda (var)
  374. (indent-to port 2)
  375. (display-c-type (final-variable-type var)
  376. (lambda (port)
  377. (writec port #\R)
  378. (write-c-identifier (variable-name var) port))
  379. port)
  380. (display " = " port)
  381. (write-c-identifier (variable-name var) port)
  382. (format port ";~%"))
  383. vars))
  384. (define (write-c-block body port indent)
  385. (write-c-block-with-args body '() port indent))
  386. (define (write-c-block-with-args body arg-vars port indent)
  387. (if (not (null? arg-vars))
  388. (write-argument-initializers arg-vars port indent))
  389. (call->c body port indent)
  390. (write-char '#\} port))
  391. ; Jump lambdas. These are generated more-or-less in the order they are
  392. ; referenced.
  393. (define (clear-lambda-generated?-flags lambdas)
  394. (for-each (lambda (l)
  395. (set-lambda-block! l #f))
  396. lambdas))
  397. (define *jumps-to-do* '())
  398. (define (note-jump-generated! proc)
  399. (if (not (lambda-block proc))
  400. (begin
  401. (set! *jumps-to-do* (cons proc *jumps-to-do*))
  402. (set-lambda-block! proc #t))))
  403. (define (write-jump-lambdas port indent)
  404. (let loop ()
  405. (let ((jumps (reverse *jumps-to-do*)))
  406. (set! *jumps-to-do* '())
  407. (for-each (lambda (jump)
  408. (jump-lambda->c jump port indent))
  409. jumps)
  410. (if (not (null? *jumps-to-do*))
  411. (loop)))))
  412. (define (jump-lambda->c node port indent)
  413. (newline port)
  414. (indent-to port indent)
  415. (display " L" port)
  416. (display (lambda-id node) port)
  417. (display ": {" port)
  418. (newline port)
  419. (write-c-block-with-args (lambda-body node)
  420. (lambda-variables node)
  421. port
  422. (+ '2 indent)))