pprint.scm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. ;;; nyacc/lang/c99/pprint.scm - C pretty-printer
  2. ;; Copyright (C) 2015-2018 Matthew R. Wette
  3. ;;
  4. ;; This library is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public
  6. ;; License as published by the Free Software Foundation; either
  7. ;; version 3 of the License, or (at your option) any later version.
  8. ;;
  9. ;; This library is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Lesser General Public License
  15. ;; along with this library; if not, see <http://www.gnu.org/licenses/>
  16. ;;; Code:
  17. (define-module (nyacc lang c99 pprint)
  18. #:export (pretty-print-c99)
  19. #:use-module ((srfi srfi-1) #:select (pair-for-each fold-right))
  20. #:use-module (nyacc lang util)
  21. #:use-module (nyacc lang sx-util)
  22. #:use-module (ice-9 pretty-print)
  23. )
  24. (cond-expand ;; for MES
  25. (guile-2 #t)
  26. (else
  27. (use-modules (ice-9 optargs))))
  28. (define op-sym
  29. (let ((ot '(("=" . eq) ("+=" . pl-eq) ("-=" . mi-eq) ("*=" . ti-eq)
  30. ("/=" . di-eq) ("%=" . mo-eq) ("<<=" . ls-eq) (">>=" . rs-eq)
  31. ("&=" . ba-eq) ("^=" . bx-eq) ("|=" bo-eq))))
  32. (lambda (name)
  33. (assoc-ref ot name))))
  34. (define op-prec
  35. ;; in order of decreasing precedence
  36. '((p-expr ident fixed float string)
  37. (comp-lit post-inc post-dec i-sel d-sel fctn-call array-ref)
  38. (de-ref ref-to neg pos not bitwise-not sizeof pre-inc pre-dec)
  39. (cast)
  40. (mul div mod)
  41. (add sub)
  42. (lshift rshift)
  43. (lt gt le ge)
  44. (eq ne)
  45. (bitwise-and)
  46. (bitwise-xor)
  47. (bitwise-or)
  48. (and)
  49. (or)
  50. (cond-expr)
  51. (assn-expr)
  52. (comma)))
  53. (define op-assc
  54. '((left array-ref d-sel i-sel post-inc post-dec comp-lit mul div mod add sub
  55. lshift rshift lt gt le ge bitwise-and bitwise-xor bitwise-or and or)
  56. (right pre-inc pre-dec sizeof bitwise-not not pos neg ref-to de-ref cast
  57. cond assn-expr)
  58. (nonassoc)))
  59. ;; @deffn {Procedure} scmchs->c scm-chr-str => c-chr-str
  60. ;; Convert 1-char scheme string into 1-char C string constant as typed by user.
  61. ;; That is, exscaped.
  62. ;; @example
  63. ;; (scmchstr->c "#x00") => "\\0"
  64. ;; @end example
  65. ;; @end deffn
  66. (define (scmchs->c scm-chr-str)
  67. (let ((ch (string-ref scm-chr-str 0)))
  68. (case ch
  69. ((#\nul) "\\0") ((#\bel) "\\a") ((#\bs) "\\b") ((#\ht) "\\t")
  70. ((#\nl) "\\n") ((#\vt) "\\v") ((#\np) "\\f") ((#\cr) "\\r") ((#\\) "\\")
  71. (else scm-chr-str))))
  72. ;; @deffn {Procedure} char->hex-list ch seed
  73. ;; to be documented
  74. ;; @end deffn
  75. (define (char->hex-list ch seed)
  76. (define (itox ival) (string-ref "0123456789ABCDEF" ival))
  77. (let loop ((res seed) (ix 8) (val (char->integer ch)))
  78. (cond
  79. ((zero? ix) (cons* #\\ #\U res))
  80. ((and (zero? val) (= ix 4)) (cons* #\\ #\u res))
  81. (else
  82. (loop (cons (itox (remainder val 16)) res) (1- ix) (quotient val 16))))))
  83. (define (esc->ch ch)
  84. (case ch ((#\nul) #\0) ((#\bel) #\a) ((#\bs) #\b) ((#\ht) #\t)
  85. ((#\nl) #\n) ((#\vt) #\v) ((#\np) #\f) ((#\cr) #\r)))
  86. ;; @deffn {Procedure} scmstr->c str
  87. ;; to be documented
  88. ;; @end deffn
  89. (define (scmstr->c str)
  90. (list->string
  91. (string-fold-right
  92. (lambda (ch chl)
  93. (cond
  94. ((char-set-contains? char-set:printing ch) (cons ch chl))
  95. ((char=? ch #\space) (cons #\space chl))
  96. ((memq ch '(#\nul #\bel #\bs #\ht #\nl #\vt #\np #\cr))
  97. (cons* #\\ (esc->ch ch) chl))
  98. (else (char->hex-list ch chl))))
  99. '() str)))
  100. ;;(define protect-expr? (make-protect-expr op-prec op-assc))
  101. ;; @deffn {Procedure} pretty-print-c99 tree [port] [options]
  102. ;; Convert and print a C99 sxml tree to the current output port.
  103. ;; The optional keyword argument @code{#:basic-offset} provides the
  104. ;; indent level, with default of 2.
  105. ;; @table code
  106. ;; @item #:basic-offset <n>
  107. ;; indent level for C code
  108. ;; @item #:per-line-prefix <string>
  109. ;; string
  110. ;; @item #:ugly #t|#f
  111. ;; pring ugly
  112. ;; @end table
  113. ;; @end deffn
  114. (define* (pretty-print-c99 tree
  115. #:optional (port (current-output-port))
  116. #:key ugly per-line-prefix (basic-offset 2))
  117. (define fmtr
  118. ((if ugly make-pp-formatter/ugly make-pp-formatter)
  119. port #:per-line-prefix per-line-prefix #:basic-offset basic-offset))
  120. (define (push-il)(fmtr 'push))
  121. (define (pop-il) (fmtr 'pop))
  122. (define (sf . args) (apply fmtr args))
  123. (define (cpp-ppx tree)
  124. (fmtr 'nlin)
  125. (sx-match tree
  126. ((define (name ,name) (args . ,args) (repl ,repl))
  127. (sf "#define ~A(" name)
  128. (pair-for-each
  129. (lambda (pair) (sf "~A" (car pair)) (if (pair? (cdr pair)) (sf ",")))
  130. args)
  131. (sf ") ~A\n" repl))
  132. ((define (name ,name) (repl ,repl))
  133. (sf "#define ~A ~A\n" name repl))
  134. ((if ,text) (sf "#if ~A\n" text))
  135. ((elif ,text) (sf "#elif ~A\n" text))
  136. ((else ,text) (sf "#else ~A\n" text))
  137. ((else) (sf "#else\n"))
  138. ((endif ,text) (sf "#endif ~A\n" text))
  139. ((endif) (sf "#endif\n"))
  140. ((include ,file . ,rest) (sf "#include ~A\n" file))
  141. ((error ,text) (sf "#error ~A\n" text))
  142. ((pragma ,text) (sf "#pragma ~A\n" text))
  143. (else (simple-format #t "\n*** pprint/cpp-ppx: NO MATCH: ~S\n" tree)))
  144. (fmtr 'nlin))
  145. (define protect-expr? (make-protect-expr op-prec op-assc))
  146. (define (unary/l op rep rval)
  147. (sf rep)
  148. (if (protect-expr? 'rt op rval)
  149. (ppx/p rval)
  150. (ppx rval)))
  151. (define (unary/r op rep lval)
  152. (if (protect-expr? 'lt op lval)
  153. (ppx/p lval)
  154. (ppx lval))
  155. (sf rep))
  156. (define (binary op rep lval rval)
  157. (if (protect-expr? 'lt op lval)
  158. (ppx/p lval)
  159. (ppx lval))
  160. (sf rep)
  161. (if (protect-expr? 'rt op rval)
  162. (ppx/p rval)
  163. (ppx rval)))
  164. ;; now ((comment xxx) (attributes "aaa;yyy;zzz"))
  165. (define (pp-attr attr)
  166. (string-join
  167. (fold-right
  168. (lambda (pair seed)
  169. (if (eqv? 'attributes (car pair))
  170. ;; FIXME: should really parse-attributes, then ppx
  171. (append (string-split (cadr pair) #\;) seed)
  172. seed))
  173. '() attr)
  174. " "))
  175. (define (struct-union-def struct-or-union attr name fields)
  176. (if name
  177. (if (pair? attr)
  178. (sf "~A ~A ~A {\n" struct-or-union (pp-attr attr) name)
  179. (sf "~A ~A {\n" struct-or-union name))
  180. (if (pair? attr)
  181. (sf "~A ~A {\n" struct-or-union (pp-attr attr))
  182. (sf "~A {\n" struct-or-union)))
  183. (push-il)
  184. (for-each ppx fields)
  185. (pop-il)
  186. (sf "}"))
  187. (define (comm+nl attr)
  188. (cond
  189. ((assq 'comment attr) => (lambda (comm) (sf " ") (ppx comm)))
  190. (else (sf "\n"))))
  191. (define (ppx/p tree) (sf "(") (ppx tree) (sf ")"))
  192. ;; TODO: comp-lit
  193. (define (ppx tree)
  194. (sx-match tree
  195. ((p-expr ,expr) (ppx expr))
  196. ((ident ,name) (sf "~A" name))
  197. ((char (@ . ,al) ,value)
  198. (let ((type (sx-attr-ref al 'type)))
  199. (cond
  200. ((not type) (sf "'~A'" (scmchs->c value)))
  201. ((string=? type "wchar_t") (sf "L'~A'" (scmchs->c value)))
  202. ((string=? type "char16_t") (sf "u'~A'" (scmchs->c value)))
  203. ((string=? type "char32_t") (sf "U'~A'" (scmchs->c value)))
  204. (else (throw 'c99-error "bad type")))))
  205. ((fixed ,value) (sf "~A" value))
  206. ((float ,value) (sf "~A" value))
  207. ((string . ,value-l)
  208. (pair-for-each
  209. (lambda (pair)
  210. (sf "\"~A\"" (scmstr->c (car pair)))
  211. (if (pair? (cdr pair)) (sf " ")))
  212. value-l))
  213. ((comment ,text)
  214. (cond
  215. ((or (string-any #\newline text) (string-suffix? " " text))
  216. (for-each (lambda (l) (sf (scmstr->c l)) (sf "\n"))
  217. (string-split (string-append "/*" text "*/") #\newline)))
  218. (else (sf (string-append "//" text "\n")))))
  219. ((scope ,expr) (sf "(") (ppx expr) (sf ")"))
  220. ((array-ref ,dim ,expr)
  221. (ppx expr) (sf "[") (ppx dim) (sf "]"))
  222. ((d-sel ,id ,ex) (binary 'd-sel "." ex id))
  223. ((i-sel ,id ,ex) (binary 'i-sel "->" ex id))
  224. ((pre-inc ,expr) (unary/l 'pre-inc "++" expr))
  225. ((pre-dec ,expr) (unary/l 'pre-dec "--" expr))
  226. ((ref-to ,expr) (unary/l 'ref-to "&" expr))
  227. ((de-ref ,expr) (unary/l 'de-ref "*" expr))
  228. ((pos ,expr) (unary/l 'pos "+" expr))
  229. ((neg ,expr) (unary/l 'neg "-" expr))
  230. ((bitwise-not ,expr) (unary/l 'bitwise-not "~" expr))
  231. ((not ,expr) (unary/l 'not "!" expr))
  232. ((sizeof-expr ,expr) (sf "sizeof(") (ppx expr) (sf ")"))
  233. ((sizeof-type ,type) (sf "sizeof(") (ppx type) (sf ")"))
  234. ((pragma ,text)
  235. (fmtr 'nlin)
  236. (sf "#pragma ~A\n" text))
  237. ((cast ,tn ,ex)
  238. (sf "(") (ppx tn) (sf ")")
  239. (if (protect-expr? 'rt 'cast ex)
  240. (ppx/p ex)
  241. (ppx ex)))
  242. ((add ,lval ,rval) (binary 'add " + " lval rval))
  243. ((sub ,lval ,rval) (binary 'sub " - " lval rval))
  244. ((mul ,lval ,rval) (binary 'mul "*" lval rval))
  245. ((div ,lval ,rval) (binary 'div "/" lval rval))
  246. ((mod ,lval ,rval) (binary 'mod "%" lval rval))
  247. ((lshift ,lval ,rval) (binary 'lshift "<<" lval rval))
  248. ((rshift ,lval ,rval) (binary 'lshift "<<" lval rval))
  249. ((lt ,lval ,rval) (binary 'lt " < " lval rval))
  250. ((gt ,lval ,rval) (binary 'gt " > " lval rval))
  251. ((le ,lval ,rval) (binary 'le " <= " lval rval))
  252. ((ge ,lval ,rval) (binary 'ge " >= " lval rval))
  253. ((eq ,lval ,rval) (binary 'eq " == " lval rval))
  254. ((ne ,lval ,rval) (binary 'ne " != " lval rval))
  255. ((bitwise-and ,lval ,rval) (binary 'bitwise-and " & " lval rval))
  256. ((bitwise-or ,lval ,rval) (binary 'bitwise-and " | " lval rval))
  257. ((bitwise-xor ,lval ,rval) (binary 'bitwise-xor " ^ " lval rval))
  258. ((and ,lval ,rval) (binary 'and " && " lval rval))
  259. ((or ,lval ,rval) (binary 'and " || " lval rval))
  260. ;; CHECK THIS
  261. ((cond-expr ,cond ,tval ,fval)
  262. (ppx cond) (sf "? ") (ppx tval) (sf ": ") (ppx fval))
  263. ((post-inc ,expr) (unary/r 'post-inc "++" expr))
  264. ((post-dec ,expr) (unary/r 'post-dec "--" expr))
  265. ;; TODO: check protection
  266. ((fctn-call ,expr ,arg-list)
  267. (if (protect-expr? 'rt 'fctn-call expr)
  268. (ppx/p expr)
  269. (ppx expr))
  270. (sf "(")
  271. (ppx arg-list)
  272. (sf ")"))
  273. ((expr-list . ,expr-l)
  274. (pair-for-each
  275. (lambda (pair)
  276. (ppx (car pair))
  277. (if (pair? (cdr pair)) (sf ", ")))
  278. expr-l))
  279. ((assn-expr ,lval ,op ,rval)
  280. (binary (car op) (simple-format #f " ~A " (cadr op)) lval rval))
  281. ;; TODO: check protection
  282. ((comma-expr . ,expr-list)
  283. (pair-for-each
  284. (lambda (pair)
  285. (cond
  286. ((pair? (cdr pair))
  287. (if (protect-expr? 'rt 'comma-expr (car pair))
  288. (ppx/p (car pair))
  289. (ppx (car pair)))
  290. (sf ", "))
  291. (else (ppx (car pair)))))
  292. expr-list))
  293. ((udecl . ,rest)
  294. (ppx `(decl . ,rest)))
  295. ((decl (@ . ,attr) ,decl-spec-list)
  296. (ppx decl-spec-list) (sf ";") (comm+nl attr))
  297. ((decl (@ . ,attr) ,decl-spec-list ,init-declr-list)
  298. (ppx decl-spec-list) (sf " ") (ppx init-declr-list) (sf ";")
  299. (comm+nl attr))
  300. ((decl-no-newline ,decl-spec-list ,init-declr-list) ; for (int i = 0;
  301. (ppx decl-spec-list) (sf " ") (ppx init-declr-list) (sf ";"))
  302. ((comp-decl (@ . ,attr) ,spec-qual-list (comp-declr-list . ,rest2))
  303. (ppx spec-qual-list) (sf " ") (ppx (sx-ref tree 2)) (sf ";")
  304. (comm+nl attr))
  305. ;; anon struct or union
  306. ((comp-decl (@ . ,attr) ,spec-qual-list)
  307. (ppx spec-qual-list) (sf ";") (comm+nl attr))
  308. ((decl-spec-list . ,dsl)
  309. (pair-for-each
  310. (lambda (dsl)
  311. (case (sx-tag (car dsl))
  312. ((stor-spec) (sf "~A" (car (sx-ref (car dsl) 1))))
  313. ((type-qual) (sf "~A" (sx-ref (car dsl) 1)))
  314. ((fctn-spec) (sf "~A" (sx-ref (car dsl) 1)))
  315. ((type-spec) (ppx (car dsl)))
  316. (else (sf "[?:~S]" (car dsl))))
  317. (if (pair? (cdr dsl)) (sf " ")))
  318. dsl))
  319. ((init-declr-list . ,rest)
  320. (pair-for-each
  321. (lambda (pair)
  322. (ppx (car pair))
  323. (if (pair? (cdr pair)) (sf ", ")))
  324. rest))
  325. ((comp-declr-list . ,rest)
  326. (pair-for-each
  327. (lambda (pair)
  328. (ppx (car pair))
  329. (if (pair? (cdr pair)) (sf ", ")))
  330. rest))
  331. ((init-declr ,declr ,item2 ,item3) (ppx declr) (ppx item2) (ppx item3))
  332. ((init-declr ,declr ,item2) (ppx declr) (ppx item2))
  333. ((init-declr ,declr) (ppx declr))
  334. ((comp-declr ,declr ,item2) (ppx declr) (ppx item2))
  335. ((comp-declr ,declr) (ppx declr))
  336. ((param-declr ,declr ,item2) (ppx declr) (ppx item2))
  337. ((param-declr ,declr) (ppx declr))
  338. ((bit-field ,ident ,expr)
  339. (ppx ident) (sf " : ") (ppx expr))
  340. ;;((type-spec ,arg)
  341. ((type-spec (@ . ,aattr) ,arg)
  342. (case (sx-tag arg)
  343. ((fixed-type) (sf "~A" (sx-ref arg 1)))
  344. ((float-type) (sf "~A" (sx-ref arg 1)))
  345. ((struct-ref) (ppx arg))
  346. ((struct-def) (if (pair? aattr) (sf " ~S" (pp-attr aattr))) (ppx arg))
  347. ((union-ref) (ppx arg))
  348. ((union-def) (if (pair? aattr) (sf " ~S" (pp-attr aattr))) (ppx arg))
  349. ((enum-ref) (ppx arg))
  350. ((enum-def) (ppx arg))
  351. ((typename) (sf "~A" (sx-ref arg 1)))
  352. ((void) (sf "void"))
  353. (else (error "missing " arg))))
  354. ((struct-ref (ident ,name)) (sf "struct ~A" name))
  355. ((union-ref (ident ,name)) (sf "union ~A" name))
  356. ((struct-def (@ . ,aattr) (ident ,name) (field-list . ,fields))
  357. (struct-union-def 'struct aattr name fields))
  358. ((struct-def (@ . ,aattr) (field-list . ,fields))
  359. (struct-union-def 'struct aattr #f fields))
  360. ((union-def (@ . ,aattr) (ident ,name) (field-list . ,fields))
  361. (struct-union-def 'union aattr name fields))
  362. ((union-def (@ . ,aattr) (field-list . ,fields))
  363. (struct-union-def 'union aattr #f fields))
  364. ((enum-ref (ident ,name))
  365. (sf "enum ~A" name))
  366. ((enum-def (ident ,name) (enum-def-list . ,edl))
  367. (sf "enum ~A " name) (ppx `(enum-def-list . ,edl))) ; SPACE ???
  368. ((enum-def (enum-def-list . ,edl))
  369. (sf "enum ") (ppx `(enum-def-list . ,edl))) ; SPACE ???
  370. ((enum-def-list . ,defns)
  371. (sf "{\n") (push-il)
  372. (for-each ppx defns)
  373. (pop-il) (sf "}"))
  374. ((enum-defn (@ . ,attr) (ident ,name) ,expr)
  375. (sf "~A = " name) (ppx expr) (sf ",") (comm+nl attr))
  376. ((enum-defn (@ . ,attr) (ident ,name))
  377. (sf "~A," name) (comm+nl attr))
  378. ;;((fctn-spec "inline")
  379. ((fctn-spec ,spec)
  380. (sf "~S " spec)) ; SPACE ???
  381. ((attribute-list . ,attrs)
  382. (sf " __attribute__((")
  383. (pair-for-each
  384. (lambda (pair)
  385. (ppx (car pair))
  386. (if (pair? (cdr pair)) (sf ",")))
  387. attrs)
  388. (sf "))"))
  389. ((attribute (ident ,name))
  390. (sf "~A" name))
  391. ((attribute (ident ,name) ,attr-expr-list)
  392. (sf "~A(" name) (ppx attr-expr-list) (sf ")"))
  393. ((attr-expr-list . ,items)
  394. (pair-for-each
  395. (lambda (pair)
  396. (ppx (car pair))
  397. (if (pair? (cdr pair)) (sf ",")))
  398. items))
  399. ((ptr-declr ,ptr ,dir-declr)
  400. (ppx ptr) (ppx dir-declr))
  401. ((pointer) (sf "*"))
  402. ((pointer ,one) (sf "*") (ppx one))
  403. ((pointer ,one ,two) (sf "*") (ppx one) (ppx two))
  404. ((type-qual-list . ,tql) ; see decl-spec-list
  405. (pair-for-each
  406. (lambda (dsl)
  407. (case (sx-tag (car dsl))
  408. ((type-qual) (sf "~A" (sx-ref (car dsl) 1)))
  409. (else (sf "[?:~S]" (car dsl))))
  410. (if (pair? (cdr dsl)) (sf " ")))
  411. tql))
  412. ((array-of ,dir-declr ,arg)
  413. (ppx dir-declr) (sf "[") (ppx arg) (sf "]"))
  414. ((array-of ,dir-declr)
  415. (ppx dir-declr) (sf "[]"))
  416. ;; MORE TO GO
  417. ((ftn-declr ,dir-declr ,param-list)
  418. (ppx dir-declr) (sf "(") (ppx param-list) (sf ")"))
  419. ((type-name ,spec-qual-list ,abs-declr)
  420. (ppx spec-qual-list) (ppx abs-declr))
  421. ((type-name ,decl-spec-list)
  422. (ppx decl-spec-list))
  423. ((abs-declr ,pointer ,dir-abs-declr) (ppx pointer) (ppx dir-abs-declr))
  424. ((abs-declr ,one-of-above) (ppx one-of-above))
  425. ;; declr-scope
  426. ((declr-scope ,abs-declr)
  427. (sf "(") (ppx abs-declr) (sf ")"))
  428. ;; declr-array dir-abs-declr
  429. ;; declr-array dir-abs-declr assn-expr
  430. ;; declr-array dir-abs-declr type-qual-list
  431. ;; declr-array dir-abs-declr type-qual-list assn-expr
  432. ((declr-array ,dir-abs-declr)
  433. (ppx dir-abs-declr) (sf "[]"))
  434. ((declr-array ,dir-abs-declr ,arg2)
  435. (ppx dir-abs-declr) (sf "[") (ppx arg2) (sf "]"))
  436. ((declr-array ,dir-abs-declr ,arg2 ,arg3)
  437. (ppx dir-abs-declr) (sf "[") (ppx arg2) (sf " ") (ppx arg3) (sf "]"))
  438. ;; declr-anon-array
  439. ;; declr-STAR
  440. ;; abs-ftn-declr
  441. ((abs-ftn-declr ,dir-abs-declr ,param-type-list)
  442. (ppx dir-abs-declr) (sf "(") (ppx param-type-list) (sf ")"))
  443. ;; anon-ftn-declr
  444. ;; initializer
  445. ((initzer ,expr)
  446. (sf " = ") (ppx expr))
  447. ;; initializer-list
  448. ((initzer-list . ,items)
  449. (sf "{") ;; or "{ "
  450. (pair-for-each
  451. (lambda (pair)
  452. (ppx (sx-ref (car pair) 1))
  453. (if (pair? (cdr pair)) (sf ", ")))
  454. items)
  455. (sf "}")) ;; or " }"
  456. ((compd-stmt (block-item-list . ,items))
  457. (sf "{\n") (push-il)
  458. (pair-for-each
  459. (lambda (pair)
  460. (let ((this (car pair)) (next (and (pair? (cdr pair)) (cadr pair))))
  461. (ppx this)
  462. (cond ;; add blank line if next is different or fctn defn
  463. ((not next))
  464. ((eqv? (sx-tag this) (sx-tag next)))
  465. ((eqv? (sx-tag this) 'comment))
  466. ((eqv? (sx-tag next) 'comment) (sf "\n")))))
  467. items)
  468. (pop-il) (sf "}\n"))
  469. ((compd-stmt-no-newline (block-item-list . ,items))
  470. (sf "{\n") (push-il) (for-each ppx items) (pop-il) (sf "} "))
  471. ;; expression-statement
  472. ((expr-stmt) (sf ";\n")) ;; add comment?
  473. ((expr-stmt (@ . ,attr) ,expr) (ppx expr) (sf ";") (comm+nl attr))
  474. ((expr) (sf "")) ; for lone expr-stmt and return-stmt
  475. ;; selection-statement
  476. ((if . ,rest)
  477. (let ((cond-part (sx-ref tree 1))
  478. (then-part (sx-ref tree 2)))
  479. (sf "if (") (ppx cond-part) (sf ") ")
  480. (ppx then-part)
  481. (let loop ((else-l (sx-tail tree 3)))
  482. (cond
  483. ((null? else-l) #t)
  484. ((eqv? 'else-if (caar else-l))
  485. (sf "else if (") (ppx (sx-ref (car else-l) 1)) (sf ") ")
  486. (ppx (sx-ref (car else-l) 2))
  487. (loop (cdr else-l)))
  488. (else
  489. (sf "else ")
  490. (ppx (car else-l)))))))
  491. ((switch ,expr (compd-stmt (block-item-list . ,items)))
  492. (sf "switch (") (ppx expr) (sf ") {\n")
  493. (for-each
  494. (lambda (item)
  495. (unless (memq (car item) '(case default)) (push-il))
  496. (ppx item)
  497. (unless (memq (car item) '(case default)) (pop-il)))
  498. items)
  499. (sf "}\n"))
  500. ;; labeled-statement
  501. ((case ,expr ,stmt)
  502. (sf "case ") (ppx expr) (sf ":\n")
  503. (push-il) (ppx stmt) (pop-il))
  504. ((default ,stmt)
  505. (sf "default:\n")
  506. (push-il) (ppx stmt) (pop-il))
  507. ;; CHECK THIS
  508. ((while ,expr ,stmt)
  509. (sf "while (") (ppx expr) (sf ") ") (ppx stmt)
  510. )
  511. ;; This does not meet the convention of "} while" on same line.
  512. ((do-while ,stmt ,expr)
  513. (sf "do ")
  514. (if (eqv? 'compd-stmt (sx-tag stmt))
  515. (ppx `(compd-stmt-no-newline ,(sx-ref stmt 1)))
  516. (ppx stmt))
  517. (sf "while (") (ppx expr) (sf ");\n"))
  518. ;; for
  519. ((for (decl . ,rest) ,test ,iter ,stmt)
  520. (sf "for (") (ppx `(decl-no-newline . ,rest))
  521. (sf " ") (ppx test) (sf "; ") (ppx iter) (sf ") ")
  522. (ppx stmt))
  523. ((for (decl . ,rest) ,expr2 ,expr3 ,stmt)
  524. (sf "for (")
  525. (ppx `(decl . ,rest)) (sf " ") (ppx expr2) (sf "; ") (ppx expr3)
  526. (sf ") ") (ppx stmt))
  527. ((for ,expr1 ,expr2 ,expr3 ,stmt)
  528. (sf "for (")
  529. (ppx expr1) (sf "; ") (ppx expr2) (sf "; ") (ppx expr3)
  530. (sf ") ") (ppx stmt))
  531. ;; jump-statement
  532. ((goto ,where)
  533. (pop-il) ; unindent
  534. (sf "goto ~A;" (sx-ref where 1))
  535. ;; comment?
  536. (sf "\n")
  537. (push-il)) ; re-indent
  538. ((continue) (sf "continue;\n"))
  539. ((break) (sf "break;\n"))
  540. ((return ,expr) (sf "return ") (ppx expr) (sf ";\n"))
  541. ((return) (sf "return;\n"))
  542. ((trans-unit . ,items)
  543. (pair-for-each
  544. (lambda (pair)
  545. (let ((this (car pair)) (next (and (pair? (cdr pair)) (cadr pair))))
  546. (ppx this)
  547. (cond ;; add blank line if next is different or fctn defn
  548. ((not next))
  549. ((eqv? (sx-tag this) (sx-tag next)))
  550. ((eqv? (sx-tag this) 'comment))
  551. ((eqv? (sx-tag next) 'comment) (sf "\n"))
  552. ((not (eqv? (sx-tag this) (sx-tag next))) (sf "\n"))
  553. ((eqv? (sx-tag next) 'fctn-defn) (sf "\n")))))
  554. items))
  555. ((fctn-defn . ,rest) ;; but not yet (knr-fctn-defn)
  556. (let* ((decl-spec-list (sx-ref tree 1))
  557. (declr (sx-ref tree 2))
  558. (compd-stmt (sx-ref tree 3)))
  559. (ppx decl-spec-list)
  560. (sf " ")
  561. (ppx declr)
  562. (sf " ")
  563. (ppx compd-stmt)))
  564. ((ptr-declr . ,rest)
  565. (ppx (sx-ref tree 1)) (ppx (sx-ref tree 2)))
  566. ((ftn-declr . ,rest)
  567. (ppx (sx-ref tree 1)) ; direct-declarator
  568. (sf "(") (ppx (sx-ref tree 2)) (sf ")"))
  569. ((param-list . ,params)
  570. (pair-for-each
  571. (lambda (pair) (ppx (car pair)) (if (pair? (cdr pair)) (sf ", ")))
  572. params))
  573. ((ellipsis) ;; should work
  574. (sf "..."))
  575. ((param-decl ,decl-spec-list ,param-declr)
  576. (ppx decl-spec-list) (sf " ") (ppx param-declr))
  577. ((param-decl ,decl-spec-list)
  578. (ppx decl-spec-list))
  579. ((cpp-stmt . ,rest)
  580. (cpp-ppx (sx-ref tree 1)))
  581. ((extern-block ,begin ,guts ,end) (ppx begin) (ppx guts) (ppx end))
  582. ((extern-begin ,lang) (sf "extern \"~A\" {\n" lang))
  583. ((extern-end) (sf "}\n"))
  584. (,_
  585. (simple-format #t "\n*** pprint/ppx: NO MATCH: ~S\n" (car tree))
  586. (pretty-print tree #:per-line-prefix " ")
  587. )))
  588. (if (not (pair? tree)) (error "expecing sxml tree"))
  589. (ppx tree)
  590. (if ugly (newline)))
  591. ;; --- last line ---