c-call.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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, Timo Harter
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/prescheme/c-call.scm
  8. ;;;
  9. ;;; Generating C code for a call
  10. (define-module (ps-compiler prescheme c-call)
  11. #:use-module (ice-9 format)
  12. #:use-module (ice-9 match)
  13. #:use-module (prescheme scheme48)
  14. #:use-module (prescheme ps-defenum)
  15. #:use-module (ps-compiler node node)
  16. #:use-module (ps-compiler node primop)
  17. #:use-module (ps-compiler node variable)
  18. #:use-module (ps-compiler prescheme c-util)
  19. #:use-module (ps-compiler prescheme external-value)
  20. #:use-module (ps-compiler prescheme flatten)
  21. #:use-module (ps-compiler prescheme primop c-primop)
  22. #:use-module (ps-compiler prescheme type)
  23. #:use-module (ps-compiler util util)
  24. #:export (call->c
  25. c-assignment
  26. indent-to
  27. c-ify
  28. c-value
  29. c-assign-to-variable
  30. write-c-identifier
  31. write-value-list
  32. write-value-list-with-extras
  33. write-value+result-var-list
  34. c-variable
  35. c-variable-no-shadowing
  36. c-variable-id
  37. c-literal-value
  38. *c-variable-id*
  39. simple-c-primop))
  40. (define (call->c node port indent)
  41. (let loop ((node node))
  42. (if (primop-call->c node port indent)
  43. (loop (lambda-body (call-arg node 0))))))
  44. (define (primop-call->c node port indent)
  45. (let ((primop (call-primop node)))
  46. (if (and (simple-c-primop? primop)
  47. (= 0 (call-exits node)))
  48. (generate-simple-assignment primop node port indent)
  49. (primop-generate-c primop node port indent))
  50. (and (= 1 (call-exits node))
  51. (not (goto-call? node)))))
  52. (define (c-value node port)
  53. (cond ((string? node)
  54. (display node port))
  55. ((not (node? node))
  56. (display node port))
  57. ((reference-node? node)
  58. (c-variable (reference-variable node) port))
  59. ((literal-node? node)
  60. (c-literal-value (literal-value node) (literal-type node) port))
  61. ((call-node? node) ;; must be simple
  62. (let ((parens? (call-needs-parens? node)))
  63. (if parens? (write-char #\( port))
  64. (primop-generate-c (call-primop node) node port 0)
  65. (if parens? (write-char #\) port))))
  66. (else
  67. (bug "odd node in C-VALUE ~S" node))))
  68. (define (c-literal-value value type port)
  69. (let ((value (cond ((integer? value) value)
  70. ((real? value) value)
  71. ((eq? value #f) 0)
  72. ((eq? value #t) 1)
  73. ((string? value) value)
  74. ((external-value? value) value)
  75. ((external-constant? value) value)
  76. ((char? value) (char->ascii value))
  77. (else
  78. (error "cannot translate literal to C ~A" value)))))
  79. (cond ((integer? value)
  80. (format port "~D" value))
  81. ((and (real? value)
  82. (inexact? value))
  83. (cond
  84. ((not (= value value))
  85. (display "PS_NAN" port))
  86. ((= value (/ 1.0 0.0))
  87. (display "PS_POS_INF" port))
  88. ((= value (/ -1.0 0.0))
  89. (display "PS_NEG_INF" port))
  90. (else display value port)))
  91. ((string? value)
  92. (c-string-constant value port))
  93. ((external-value? value)
  94. (display (external-value-string value) port))
  95. ((external-constant? value)
  96. (display (external-constant-c-string value) port))
  97. (else
  98. (display value port)))))
  99. (define (c-string-constant string port)
  100. (write-char #\" port)
  101. (do ((i 0 (+ i 1)))
  102. ((= i (string-length string)))
  103. (let ((char (string-ref string i)))
  104. (case char
  105. ((#\newline)
  106. (write-char #\\ port)
  107. (write-char #\n port))
  108. ((#\")
  109. (write-char #\\ port)
  110. (write-char #\" port))
  111. ((#\\)
  112. (write-char #\\ port)
  113. (write-char #\\ port))
  114. (else
  115. (write-char char port)))))
  116. (write-char #\" port))
  117. ;; (case (base-type-size (maybe-follow-uvar type))
  118. ;; ((1)
  119. ;; (let ((new-value (if (>= value 0)
  120. ;; (bitwise-and value 255)
  121. ;; (error "can't translate negative character constants to C ~S"
  122. ;; value))))
  123. ;; (format port "'\\~D~D~D'"
  124. ;; (remainder (quotient new-value 64) 8)
  125. ;; (remainder (quotient new-value 8) 8)
  126. ;; (remainder new-value 8))))
  127. ;; ((2)
  128. ;; (format port "~D" value))
  129. ;; ((4)
  130. ;; (format port "~DL" value))
  131. ;; (else
  132. ;; (error "cannot translate literal type to C ~S" type)))
  133. ;; Cut down on the number of unnecessary parentheses. We don't go so far as
  134. ;; to pay attention to C's precedence rules.
  135. (define (call-needs-parens? call)
  136. (and (not (and (eq? 'contents (primop-id (call-primop call)))
  137. (eq? 'global (literal-value (call-arg call loc/type)))))
  138. (let ((parent (node-parent call)))
  139. (and (node? parent)
  140. (call-node? parent)
  141. (not (eq? 'let
  142. (primop-id (call-primop parent))))))))
  143. ;; Each local variable has a unique integer used to disambiguate in the
  144. ;; C code. Using our own, instead of what variables already have, keeps
  145. ;; the numbers smaller and more readable.
  146. (define *c-variable-id* '0)
  147. (define (next-c-variable-id)
  148. (let ((id *c-variable-id*))
  149. (set! *c-variable-id* (+ *c-variable-id* 1))
  150. id))
  151. (define (c-variable-id var)
  152. (if (integer? (variable-generate var))
  153. (variable-generate var)
  154. (let ((id (next-c-variable-id)))
  155. (set! *local-vars* (cons var *local-vars*))
  156. (set-variable-generate! var id)
  157. id)))
  158. (define (c-variable var port)
  159. (really-c-variable var port #t))
  160. (define (c-variable-no-shadowing var port)
  161. (really-c-variable var port #f))
  162. (define (really-c-variable var port shadow?)
  163. (cond ((string? var)
  164. (display var port))
  165. ((symbol? var)
  166. (display var port))
  167. ((not (variable? var))
  168. (bug "funny value for C-VARIABLE ~S" var))
  169. ((not (variable-binder var))
  170. (cond ((and shadow?
  171. (memq? 'shadowed (variable-flags var)))
  172. (writec port '#\R))
  173. ((generated-top-variable? var)
  174. (writec port '#\H)))
  175. (write-c-identifier (variable-name var) port)
  176. (if (generated-top-variable? var)
  177. (display (c-variable-id var) port)))
  178. (else
  179. ;; (if (= (c-variable-id var) 944)
  180. ;; (breakpoint "writing 944"))
  181. (write-c-identifier (variable-name var) port)
  182. (write-char '#\_ port)
  183. (display (c-variable-id var) port)
  184. (write-char '#\X port))))
  185. ;;==============================================================================;
  186. ;; Scheme identifiers contain many characters that are not legal in C
  187. ;; identifiers. Luckily C is case-sensitive and Scheme is not.
  188. (define char-translations
  189. (let* ((count ascii-limit)
  190. (string (make-string count)))
  191. (do ((i '0 (+ i '1)))
  192. ((>= i count))
  193. (let ((char (ascii->char i)))
  194. (string-set! string i
  195. (cond ((and (char-alphabetic? char)
  196. (char=? char
  197. (string-ref (symbol->string
  198. (string->symbol
  199. (list->string
  200. (list char))))
  201. 0)))
  202. (char-downcase char))
  203. ((char-numeric? char)
  204. char)
  205. (else
  206. (ascii->char 0))))))
  207. (string-set! string (char->ascii '#\+) '#\A)
  208. (string-set! string (char->ascii '#\!) '#\B)
  209. (string-set! string (char->ascii '#\:) '#\C)
  210. (string-set! string (char->ascii '#\.) '#\D)
  211. (string-set! string (char->ascii '#\=) '#\E)
  212. (string-set! string (char->ascii '#\>) '#\G)
  213. ;; used for flattened closures H
  214. ;; used for computed-goto J
  215. ;; precedes C keywords K
  216. (string-set! string (char->ascii '#\<) '#\L)
  217. (string-set! string (char->ascii '#\?) '#\P)
  218. (string-set! string (char->ascii '#\%) '#\Q)
  219. (string-set! string (char->ascii '#\*) '#\S)
  220. ;; used for tail-recursive procedures T
  221. (string-set! string (char->ascii '#\/) '#\U)
  222. (string-set! string (char->ascii '#\#) '#\W)
  223. ;; follows lexical identifiers X
  224. ;; used by the multi-procedure block code Z
  225. (string-set! string (char->ascii '#\-) '#\_)
  226. string))
  227. ;; This needs to check for C keywords (just precede with K)
  228. (define (write-c-identifier symbol port)
  229. (if (table-ref c-keywords symbol)
  230. (writec port '#\K))
  231. (let ((string (symbol->string symbol)))
  232. (do ((i 0 (+ i 1)))
  233. ((>= i (string-length string)))
  234. (let* ((char (string-ref string i))
  235. (out (string-ref char-translations (char->ascii char))))
  236. (if (= 0 (char->ascii out))
  237. (bug "cannot translate ~S from ~A into C" char string)
  238. (writec port out))))
  239. (values)))
  240. (define (c-ify symbol)
  241. (call-with-string-output-port
  242. (lambda (port)
  243. (write-c-identifier symbol port))))
  244. (define c-keywords (make-table))
  245. (for-each (lambda (k)
  246. (table-set! c-keywords k #t))
  247. '(
  248. auto double int struct
  249. break else long switch
  250. case enum register typedef
  251. char extern return union
  252. const float short unsigned
  253. continue for signed void
  254. default goto sizeof volatile
  255. do if static while
  256. ))
  257. ;;==============================================================================;
  258. (define (simple-c-primop op call port)
  259. (case (call-arg-count call)
  260. ((1)
  261. (generate-simple-c-monop-call op (call-arg call 0) port))
  262. ((2)
  263. (match (call-args call)
  264. (#(arg1 arg2)
  265. (generate-simple-c-binop-call op arg1 arg2 port))))
  266. (else
  267. (bug "funny call to SIMPLE-C-PRIMOP ~S" call))))
  268. (define (generate-simple-c-binop-call op arg1 arg2 port)
  269. (c-value arg1 port)
  270. (writec port '#\space)
  271. (display op port)
  272. (writec port '#\space)
  273. (c-value arg2 port)
  274. (values))
  275. (define (generate-simple-c-monop-call op arg1 port)
  276. (display op port)
  277. (writec port '#\space)
  278. (c-value arg1 port)
  279. (values))
  280. (define (generate-simple-assignment primop call port indent)
  281. (let ((var (car (lambda-variables (call-arg call 0)))))
  282. (c-assign-to-variable var port indent)
  283. (primop-generate-c primop call port #f)
  284. (writec port '#\;)
  285. (values)))
  286. (define (c-assignment var value port indent)
  287. (c-assign-to-variable var port indent)
  288. (c-value value port)
  289. (writec port '#\;))
  290. (define (c-assign-to-variable var port indent)
  291. (indent-to port indent)
  292. (cond ((or (not (variable? var))
  293. (and (or (used? var)
  294. (global-variable? var))
  295. (not (eq? type/unit (final-variable-type var)))))
  296. (c-variable var port)
  297. (display " = " port))))
  298. ;;==============================================================================;
  299. (define (known-variable-reference node)
  300. (cond ((reference-node? node)
  301. (let ((var (reference-variable node)))
  302. (if (global-variable? var) var #f)))
  303. (else #f)))
  304. (define (write-value-list args start port)
  305. (writec port '#\()
  306. (really-write-value-list args start '() port)
  307. (writec port '#\)))
  308. (define (write-value-list-with-extras args start extras port)
  309. (writec port '#\()
  310. (really-write-value-list args start extras port)
  311. (writec port '#\)))
  312. (define (really-write-value-list args start extras port)
  313. (let ((len (vector-length args)))
  314. (cond ((> len start)
  315. (c-value (vector-ref args start) port)
  316. (do ((i (+ start '1) (+ i '1)))
  317. ((>= i len) (values))
  318. (writec port '#\,)
  319. (writec port '#\space)
  320. (c-value (vector-ref args i) port))
  321. (write-comma-value-list extras port))
  322. ((not (null? extras))
  323. (c-value (car extras) port)
  324. (write-comma-value-list (cdr extras) port)))))
  325. (define (write-comma-value-list args port)
  326. (for-each (lambda (arg)
  327. (writec port '#\,)
  328. (writec port '#\space)
  329. (c-value arg port))
  330. args))
  331. (define (write-value+result-var-list args start vars port)
  332. (writec port '#\()
  333. (really-write-value-list args start '() port)
  334. (cond ((not (null? vars))
  335. (if (> (vector-length args) start)
  336. (display ", " port))
  337. (writec port #\&)
  338. (c-variable (car vars) port)
  339. (for-each (lambda (var)
  340. (display ", &" port)
  341. (c-variable var port))
  342. (cdr vars))))
  343. (writec port #\)))
  344. (define (c-system-call proc args port)
  345. (display proc port)
  346. (writec port '#\()
  347. (if (not (null? args))
  348. (let loop ((args args))
  349. (c-value (car args) port)
  350. (cond ((not (null? (cdr args)))
  351. (writec port '#\,)
  352. (writec port '#\space)
  353. (loop (cdr args))))))
  354. (writec port '#\))
  355. (values))
  356. (define (indent-to port indent)
  357. (if (> (current-column port) indent)
  358. (newline port))
  359. (do ((c (current-column port) (+ c 1)))
  360. ((>= c indent))
  361. (write-char #\space port)))