43ab78bafd0fbf4542a39d5f8102c84aa03838aa
[mes.git] / module / nyacc / lang / c99 / util2.scm
1 ;;; nyacc/lang/c99/util2.scm - C processing code
2 ;;; 
3 ;;; Copyright (C) 2015,2016 Matthew R. Wette
4 ;;;
5 ;;; This program is free software: you can redistribute it and/or modify
6 ;;; it under the terms of the GNU General Public License as published by 
7 ;;; the Free Software Foundation, either version 3 of the License, or 
8 ;;; (at your option) any later version.
9 ;;;
10 ;;; This program is distributed in the hope that it will be useful,
11 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of 
12 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ;;; GNU General Public License for more details.
14 ;;;
15 ;;; You should have received a copy of the GNU General Public License
16 ;;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 ;; utilities for processing output trees
19
20 ;; The idea is to convert declarations into something like
21 ;; @example
22 ;; const char *args[21];  /* command arguments */
23 ;; @end example
24 ;; @noindent
25 ;; into
26 ;; @example
27 ;; ("args" (comment " command arguments ")
28 ;;  (array-of 21) (pointer-to) (fixed "char"))
29 ;; @end example
30 ;; @noindent
31 ;; or without the comment.  It is a question whether we need the fixed part.
32 ;; In addition, we want to reduce to a set of canonical types.  So something
33 ;; like @code{foo_t} should be expanded.
34
35 ;; KEEPING STRUCTS ENUMS etc
36 ;; if have typename and want to keep it, then change
37 ;;   (typename "foo_t")
38 ;; to
39 ;;   (typename (@ (base "struct")) "foo_t")
40
41 ;; ALSO
42 ;;  (make-proxy comp-udecl) => udecl
43 ;;  (revert-proxy udecl) => comp-udecl
44
45 (define-module (nyacc lang c99 util2)
46   #:export (tree->udict
47             stripdown stripdown-2
48             udecl->mspec
49             udecl->mspec/comm
50
51             unwrap-decl
52             canize-enum-def-list
53             fix-fields
54             fixed-width-int-names
55
56             match-decl match-comp-decl
57             declr->ident
58             expand-decl-typerefs
59             )
60   #:use-module (nyacc lang c99 pprint)
61   #:use-module (ice-9 pretty-print)
62   #:use-module (srfi srfi-1)
63   #:use-module ((sxml fold) #:select (foldts foldts*))
64   #:use-module (sxml match)
65   #:use-module (nyacc lang util)
66   #:use-module (nyacc lang c99 pprint)
67   )
68
69 ;; Use the term @dfn{udecl}, or unit-declaration, for a declaration which has
70 ;; only one decl-item.  That is where,
71 ;; @example
72 ;; @end example
73 ;; (decl (decl-spec-list ...) (init-declr-list (init-declr ...) ...))
74 ;; @noindent
75 ;; has been replaced by
76 ;; (decl (decl-spec-list ...) (init-declr ...))
77 ;; ...
78 ;; @example
79 ;; @end example
80
81 ;; mspec is
82 ;; ("foo" (pointer-to) (array-of 3) (fixed-type "unsigned int"))
83 ;; which can be converted to
84 ;; ("(*foo) (array-of 3) (fixed-type "unsigned int"))
85 ;; which can be converted to
86 ;; (("((*foo)[0])" (fixed-type "unsigned int"))
87 ;;  ("((*foo)[1])" (fixed-type "unsigned int"))
88 ;;  ("((*foo)[2])" (fixed-type "unsigned int"))
89
90 ;; may need to replace (typename "int32_t") with (fixed-type "int32_t")
91
92
93 ;; @deffn declr->ident declr => (ident "name")
94 ;; just match the declarator
95 ;; (init-declr <declr> [<initzer>])
96 ;; See also: declr->id-name in body.scm.
97 (define (declr->ident declr)
98   (sxml-match declr
99     ((init-declr ,declr . ,rest) (declr->ident declr))
100     ((comp-declr ,declr) (declr->ident declr))
101     ((param-declr ,declr) (declr->ident declr))
102     ((ident ,name) declr)
103     ((array-of ,dir-declr ,array-spec) (declr->ident dir-declr))
104     ((array-of ,dir-declr) (declr->ident dir-declr))
105     ((ptr-declr ,pointer ,dir-declr) (declr->ident dir-declr))
106     ((ftn-declr ,dir-declr ,rest ...) (declr->ident dir-declr))
107     ((scope ,declr) (declr->ident declr))
108     (,otherwise (throw 'util-error "c99/util2: unknown declarator: " declr))))
109
110 ;; @deffn unwrap-decl decl seed => seed
111 ;; This is a fold to break up multiple declarators.
112 ;; @example
113 ;; (decl (decl-spec-list ...) (init-declr-list (init-declr ...) ...))
114 ;; =>
115 ;; ((decl (decl-spec-list ...) (init-declr ...))
116 ;;  (decl (decl-spec-list ...) (init-declr ...))
117 ;;  ...)
118 ;; @end example
119 (define (unwrap-decl decl seed)
120   (cond
121    ((not (eqv? 'decl (car decl))) seed)
122    ((< (length decl) 3) seed)           ; this should catch struct-ref etc.
123    (else
124     (let* ((tag (sx-ref decl 0))
125            (attr (sx-attr decl))
126            (spec (sx-ref decl 1))       ; (decl-spec-list ...)
127            (id-l (sx-ref decl 2))       ; (init-declr-list ...)
128            (tail (sx-tail decl 3)))     ; comment
129       (let iter ((res seed) (idl (cdr id-l)))
130         (if (null? idl) res
131             (let* ((declr (sx-ref (car idl) 1))
132                    (ident (declr->ident declr))
133                    (name (cadr ident)))
134               (iter (cons (if attr
135                               (cons* tag attr spec (car idl) tail)
136                               (cons* tag spec (car idl) tail))
137                           res)
138                     (cdr idl)))))))))
139
140
141 ;; @deffn tree->udict tree => udict
142 ;; Turn a C parse tree into a assoc-list of names and definitions.
143 ;; This will unwrap @code{init-declr-list} into list of decls w/
144 ;; @code{init-declr}.
145 ;; BUG: need to add struct and union defn's: struct foo { int x; };
146 ;; how to deal with this
147 ;; lookup '(struct . "foo"), "struct foo", ???
148 ;; wanted "struct" -> dict but that is not great
149 ;; solution: match-decl => '(struct . "foo") then filter to generate
150 ;; ("struct" ("foo" . decl) ..)
151 ;; ("union" ("bar" . decl) ..)
152 (define (tree->udict tree)
153   (if (pair? tree)
154       ;;(reverse (fold match-decl '() (cdr tree)))
155       (fold match-decl '() (cdr tree))
156       '()))
157
158 ;; @deffn match-decl decl seed
159 ;; This procedure is intended to be used with @code{fold}.  It breaks up
160 ;; up the init-declr-list into individual init-declr items and associates
161 ;; with the identifier being declared.  So this is a fold iterator to
162 ;; provide a dictionary of declared names.
163 ;; @example
164 ;; (decl (decl-spec-list ...) (init-declr-list (init-declr ...) ...))
165 ;; @end example
166 ;; @noindent
167 ;; has been replaced by
168 ;; @example
169 ;; (decl (decl-spec-list ...) (init-declr ...))
170 ;; (decl (decl-spec-list ...) ...)
171 ;; @end example
172 ;; Here we generate a dictionary of all declared items:
173 ;; @example
174 ;; (let* ((sx0 (with-input-from-file src-file parse-c))
175 ;;        (sx1 (merge-inc-trees! sx0))
176 ;;        (name-dict (fold match-decl-1 '() (cdr sx1))))
177 ;; @end example
178 (define (match-decl decl seed)
179   (let* ((tag (sx-ref decl 0)) (attr (sx-attr decl)))
180     (case tag
181       ((decl)
182        (let* ((spec (sx-ref decl 1))    ; (decl-spec-list ...)
183               (tbd (sx-ref decl 2)))    ; (init-declr-list ...) OR ...
184          (cond
185           ((or (not tbd) (eqv? 'comment (sx-tag tbd)))
186            (display "ISSUE: some decls have no init-declr-list\n")
187            ;; no init-declr-list => struct or union def
188            ;;(display "spec:\n") (pretty-print spec)
189            (sxml-match spec
190              ((decl-spec-list
191                (type-spec
192                 (struct-def (ident ,name) . ,rest2) . ,rest1))
193               (acons `(struct . ,name) decl seed))
194              ((decl-spec-list
195                (type-spec
196                 (union-def (ident ,name) . ,rest2) . ,rest1))
197               (acons `(union . ,name) decl seed))
198              (,otherwise
199               (display "otherwise:\n") (pretty-print (cdr spec))
200               seed)))
201           (else ;; decl with init-declr-list
202            (let* ((id-l tbd) (tail (sx-tail decl 3)))
203              (let iter ((res seed) (idl (cdr id-l)))
204                (if (null? idl) res
205                    (let* ((declr (sx-ref (car idl) 1))
206                           (ident (declr->ident declr))
207                           (name (cadr ident)))
208                      (iter
209                       (acons name
210                              (if attr
211                                  (cons* tag attr spec (car idl) tail)
212                                  (cons* tag spec (car idl) tail))
213                              res)
214                       (cdr idl))))))))))
215       (else seed))))
216
217 ;; @deffn match-comp-decl decl seed
218 ;; This will turn
219 ;; @example
220 ;; (comp-decl (decl-spec-list (type-spec "int"))
221 ;;            (comp-decl-list (comp-decl (ident "a")) (comp-decl (ident "b"))))
222 ;; @end example
223 ;; @noindent
224 ;; into
225 ;; @example
226 ;; ("a" . (comp-decl (decl-spec-list ...) (comp-decl (ident "a"))))
227 ;; ("b" . (comp-decl (decl-spec-list ...) (comp-decl (ident "b"))))
228 ;; @end example
229 ;; @noindent
230 ;; This is coded to be used with fold-right in order to preserve order
231 ;; in @code{struct} and @code{union} field lists.
232 (define (match-comp-decl decl seed)
233   (if (not (eqv? 'comp-decl (car decl))) seed
234       (let* ((tag (sx-ref decl 0))
235              (attr (sx-attr decl))
236              (spec (sx-ref decl 1))     ; (type-spec ...)
237              (id-l (sx-ref decl 2))     ; (init-declr-list ...)
238              (tail (sx-tail decl 3)))   ; opt comment, different here
239         ;;(simple-format #t "1: ~S\n" id-l)
240         (let iter ((res seed) (idl (cdr id-l)))
241           (if (null? idl) res
242               (let* ((declr (sx-ref (car idl) 1))
243                      (ident (declr->ident declr))
244                      (name (cadr ident)))
245                 ;;(pretty-print `(comp-decl ,spec ,(car idl) . ,tail))
246                 (acons name
247                        (if attr
248                            (cons* tag attr spec (car idl) tail)
249                            (cons* tag spec (car idl) tail))
250                        (iter res (cdr idl)))))))))
251
252 ;; @deffn find-special udecl-alist seed => ..
253 ;; NOT DONE
254 ;; @example
255 ;; '((struct . ("foo" ...) ...)
256 ;;   (union . ("bar" ...) ...)
257 ;;   (enum . ("bar" ...) ...)
258 ;;   seed)
259 ;; @end example
260 (define (find-special udecl-alist seed)
261   (let iter ((struct '()) (union '()) (enum '()) (udal udecl-alist))
262     (if (null? udal) (cons* (cons 'struct struct)
263                           (cons 'union union)
264                           (cons 'enum enum)
265                           seed)
266         '())))
267
268 (define tmap-fmt
269   '(("char" "%hhd")
270     ("unsigned char" "%hhu")
271     ("short int" "%hd")
272     ("unsigned short int" "%hu")
273     ("int" "%d")
274     ("unsigned int" "%u")
275     ("long int" "%ld")
276     ("unsigned long int" "%lu")
277     ("long long int" "%lld")
278     ("unsigned long long int" "%llu")))
279
280 (define fixed-width-int-names
281   '("int8_t" "uint8_t" "int16_t" "uint16_t"
282     "int32_t" "uint32_t" "int64_t" "uint64_t"))
283
284 ;; @deffn typedef-decl? decl)
285 (define (typedef-decl? decl)
286   (sxml-match decl
287     ((decl (decl-spec-list (stor-spec (typedef)) . ,r1) . ,r2) #t)
288     (,otherwise #f)))
289
290 ;; @deffn splice-declarators orig-declr tdef-declr => 
291 ;; Splice the original declarator into the typedef declarator.
292 ;; This is a helper for @code{expand-*-typename-ref} procecures.
293 (define (splice-declarators orig-declr tdef-declr)
294   
295   (define (fD seed tree)                ; => (values seed tree)
296     (sxml-match tree
297       ((param-list . ,rest) (values tree '())) ; don't process
298       ((ident ,name) (values (reverse (cadr orig-declr)) '())) ; replace
299       (,otherwise (values '() tree))))
300
301   (define (fU seed kseed tree)
302     (let ((ktree (case (car kseed)
303                    ((param-list ident) kseed)
304                    (else (reverse kseed)))))
305       (if (null? seed) ktree (cons ktree seed))))
306
307   (define (fH seed tree)
308     (cons tree seed))
309
310   ;; This cons transfers the tag from orig-declr to the result.
311   (cons
312    (car orig-declr)                     ; init-declr or comp-declr
313    (cdr (foldts* fD fU fH '() tdef-declr)))) ; always init-declr
314
315
316 ;; @deffn repl-typespec decl-spec-list replacement
317 ;; This is a helper for expand-decl-typerefs
318 (define (repl-typespec decl-spec-list replacement)
319   (fold-right
320    (lambda (item seed)
321      (cond ((symbol? item) (cons item seed))
322            ((eqv? 'type-spec (car item))
323             (if (pair? (car replacement))
324                 (append replacement seed)
325                 (cons replacement seed)))
326            (else (cons item seed))))
327    '() decl-spec-list))
328
329 ;; @deffn expand-decl-typerefs udecl udecl-dict => udecl
330 ;; Given a declaration or component-declaration, expand all typename,
331 ;; struct, union and enum refs.
332 ;; @example
333 ;; typedef const int  (*foo_t)(int a, double b);
334 ;; extern    foo_t    fctns[2];
335 ;; @noindent
336 ;; This routine should create an init-declarator associated with
337 ;; @end example
338 ;; extern {const int}  (*{fctns[2]})(int a, double b);
339 ;; @end example
340 ;; @noindent
341 ;; Cool. Eh? (but is it done?)
342 (define* (expand-decl-typerefs udecl udecl-dict #:key (keep '()))
343   (display "FIXME: some decls have no init-declr-list\n")
344   ;; between adding (init-declr-list) to those or having predicate
345   ;; (has-init-declr? decl)
346   (let* ((tag (sx-tag udecl))           ; decl or comp-decl
347          (attr (sx-attr udecl))         ; (@ ...)
348          (specl (sx-ref udecl 1))       ; decl-spec-list
349          (declr (or (sx-find 'init-declr udecl)
350                     (sx-find 'comp-declr udecl)))
351          (tail (if declr (sx-tail udecl 3) (sx-tail udecl 2))) ; opt comment
352          (tspec (cadr (sx-find 'type-spec specl))))
353     ;;(simple-format #t "=D> ~S\n" decl-spec-list)
354     ;;(simple-format #t "init-declr: ~S\n" init-declr)
355     (case (car tspec)
356       ((typename)
357        (cond
358         ((member (cadr tspec) keep)
359          udecl)
360         #;((member (cadr tspec) fixed-width-int-names)
361          ;; Convert it to @code{fixed-type}.
362          (let* ((name (cadr tspec))
363                 (fixd-tspec `(type-spec (fixed-type ,name)))
364                 (fixd-specl (repl-typespec specl fixd-tspec))
365                 ;; TODO add attr
366                 (fixed-udecl (cons* tag fixd-specl declr tail)))
367            ;;(expand-decl-typerefs fixed-udecl udecl-dict))) ; not needed ?
368            fixed-udecl))
369         (else
370          ;; splice in the typedef
371          (let* ((name (sx-ref tspec 1))
372                 (decl (assoc-ref udecl-dict name)) ; decl for typename
373                 (tdef-specl (sx-ref decl 1)) ; decl-spec-list for typename
374                 (tdef-declr (sx-ref decl 2)) ; init-declr for typename
375                 ;; splice the typedef specifiers into target:
376                 (fixd-specl (repl-typespec specl (sx-tail tdef-specl 2)))
377                 (fixd-declr (splice-declarators declr tdef-declr))
378                 (fixed-udecl (cons* tag fixd-specl fixd-declr tail)))
379            (expand-decl-typerefs fixed-udecl udecl-dict #:keep keep)))))
380
381       ((struct-ref union-ref)
382        (simple-format (current-error-port)
383                       "+++ c99/util2: struct/union-ref: more to do?\n")
384        ;;(simple-format #t "\nstruct-ref:\n") (pretty-print udecl)
385        udecl)
386
387       ((struct-def union-def)
388        (let* ((ident (sx-find 'ident tspec))
389               (field-list (sx-find 'field-list tspec))
390               (orig-flds (cdr field-list))
391               (unit-flds (map cdr (fold-right match-comp-decl '() orig-flds)))
392               (fixd-flds (map
393                           (lambda (fld)
394                             (expand-decl-typerefs fld udecl-dict #:keep keep))
395                           unit-flds))
396               (fixd-tspec
397                (if #f ;;ident
398                    `(type-spec (struct-def ,ident (field-list ,@fixd-flds)))
399                    `(type-spec (struct-def (field-list ,@fixd-flds)))))
400               (fixd-specl (repl-typespec specl fixd-tspec)))
401          (if declr (cons* tag fixd-specl declr tail)
402              (cons* tag fixd-specl tail))))
403       
404       ((enum-def)
405        (let* ((enum-def-list (sx-find 'enum-def-list tspec))
406               (fixd-def-list (canize-enum-def-list enum-def-list))
407               (fixd-tspec `(type-spec (enum-def ,fixd-def-list)))
408               (fixd-specl (repl-typespec specl fixd-tspec))
409               (fixed-decl (cons* tag fixd-specl declr tail))) ;; !!!
410          fixed-decl))
411
412       ((enum-ref)
413        (simple-format (current-error-port) "chack: enum-ref NOT DONE\n")
414        udecl)
415
416       (else udecl))))
417   
418 ;; @deffn canize-enum-def-list
419 ;; Fill in constants for all entries of an enum list.
420 (define (canize-enum-def-list enum-def-list)
421   (define (get-used edl)
422     (let iter ((uzd '()) (edl edl))
423          (cond
424           ((null? edl) uzd)
425           ((assq-ref (cdar edl) 'p-expr) =>
426            (lambda (x)
427              (iter (cons (string->number (cadar x)) uzd) (cdr edl))))
428           (else
429            (iter uzd (cdr edl))))))
430   (let ((used (get-used (cdr enum-def-list))))
431     (let iter ((rez '()) (ix 0) (edl (cdr enum-def-list)))
432       (cond
433        ((null? edl) (cons (car enum-def-list) (reverse rez)))
434        ((assq-ref (cdar edl) 'p-expr)
435         (iter (cons (car edl) rez) ix (cdr edl)))
436        (else
437         (let* ((ix1 (let iter ((ix (1+ ix)))
438                       (if (memq ix used) (iter (1+ ix)) ix)))
439                (is1 (number->string ix1)))
440           (iter (cons (append (car edl) `((p-expr (fixed ,is1)))) rez)
441                 ix1 (cdr edl))))))))
442
443 ;; @deffn stripdown udecl decl-dict => decl
444 ;; 1) remove stor-spec
445 ;; 2) expand typenames
446 ;; @example
447 ;; typedef int *x_t;
448 ;; x_t a[10];
449 ;; (spec (typename x_t)) (init-declr (array-of 10 (ident a)))
450 ;; (spec (typedef) (fixed-type "int")) (init-declr (pointer) (ident "x_t"))
451 ;; =>
452 ;; [TO BE DOCUMENTED]
453 ;; @end example
454 (define* (stripdown udecl decl-dict #:key (keep '()))
455
456   ;;(define strip-list '(stor-spec type-qual comment))
457   (define strip-list '(stor-spec type-qual))
458
459   (define (fsD seed tree)
460     '())
461
462   (define (fsU seed kseed tree)
463     (if (memq (car tree) strip-list)
464         seed
465         (if (null? seed)
466             (reverse kseed)
467             (cons (reverse kseed) seed))))
468         
469   (define (fsH seed tree)
470     (cons tree seed))
471
472   (let* ((xdecl (expand-decl-typerefs udecl decl-dict #:keep keep))
473          (tag (sx-tag xdecl))
474          (attr (sx-attr xdecl))
475          (specl (sx-ref xdecl 1))
476          (declr (sx-ref xdecl 2))
477          (specl1 (foldts fsD fsU fsH '() specl)))
478     (list tag specl1 declr)))
479
480 ;; This one experimental for guile ffi.
481 (define* (stripdown-2 udecl decl-dict #:key (keep '()))
482
483   ;;(define strip-list '(stor-spec type-qual comment))
484   (define strip-list '(stor-spec type-qual))
485
486   (define (fsD seed tree)
487     '())
488
489   (define (fsU seed kseed tree)
490     (if (memq (car tree) strip-list)
491         seed
492         (if (null? seed)
493             (reverse kseed)
494             (cons (reverse kseed) seed))))
495         
496   (define (fsH seed tree)
497     (cons tree seed))
498
499   (let* ((speclt (sx-tail udecl 1)))    ; decl-spec-list tail
500     ;; don't expand typedefs, structure specs etc,
501     (cond
502      ((and (eqv? 'stor-spec (caar speclt))
503            (eqv? 'typedef (cadar speclt)))
504       udecl)
505      ;; lone struct ref
506      (else
507       (let* ((xdecl (expand-decl-typerefs udecl decl-dict #:keep keep))
508              (tag (sx-tag xdecl))
509              (attr (sx-attr xdecl))
510              (specl (sx-ref xdecl 1))
511              (declr (sx-ref xdecl 2))
512              (specl1 (foldts fsD fsU fsH '() specl)))
513         (list tag specl1 declr))))
514       ))
515
516
517 ;; @deffn udecl->mspec sudecl
518 ;; Turn a stripped-down unit-declaration into an m-spec.
519 ;; This assumes decls have been run through @code{stripdown}.
520 (define (udecl->mspec decl . rest)
521
522   (define (cnvt-array-size size-spec)
523     (simple-format #t "cnvt-array-size\n")
524     (with-output-to-string (lambda () (pretty-print-c99 size-spec))))
525
526   (define (unwrap-specl specl)
527     (let ((tspec (cadadr specl)))
528       ;;(simple-format #t "tspec:\n") (pretty-print tspec)
529       (sxml-match tspec
530         ((xxx-struct-def (field-list . ,rest))
531          `(struct-def ,@rest))
532         (,otherwise
533          tspec))))
534     
535   (define (unwrap-declr declr)
536     (sxml-match declr
537       ((ident ,name)
538        (list name))
539       ((init-declr ,item)
540        (unwrap-declr item))
541       ((comp-declr ,item)
542        (unwrap-declr item))
543       ((ptr-declr (pointer . ,r) ,dir-declr)
544        (cons '(pointer-to) (unwrap-declr dir-declr)))
545       ((array-of ,dir-declr ,size)
546        (cons `(array-of ,(cnvt-array-size size)) (unwrap-declr dir-declr)))
547       ((ftn-declr ,dir-declr ,params)
548        (cons '(function-returning) (unwrap-declr dir-declr)))
549       ((scope ,expr)
550        (unwrap-declr expr))
551       (,otherwise
552        (simple-format #t "unwrap-declr: OTHERWISE\n") (pretty-print otherwise)
553        ;; failed got: (array-of (ident "foo")) FROM const char foo[];
554        #f)))
555
556   (define (find-type-spec decl-spec-list)
557     (let iter ((tsl (cdr decl-spec-list)))
558       (if (eqv? 'type-spec (caar tsl)) (car tsl)
559           (iter (cdr tsl))))) 
560   
561   (let* ((decl-dict (if (pair? rest) (car rest) '()))
562          (specl (sx-ref decl 1))
563          (declr (sx-ref decl 2))
564          (comm (sx-ref decl 3))
565          (m-specl (unwrap-specl specl))
566          (m-declr (unwrap-declr declr))
567          (m-decl (reverse (cons m-specl m-declr))))
568     m-decl))
569
570 (define* (udecl->mspec/comm decl #:optional (dict '()) #:key (def-comm ""))
571   (let* ((comm (sx-ref decl 3))
572          (spec (udecl->mspec decl dict)))
573     (cons* (car spec) (or comm `(comment ,def-comm)) (cdr spec))))
574
575 ;; @deffn fix-fields flds => flds
576 ;; This will take a list of fields from a struct and remove lone comments.
577 ;; If a field following a lone comment has no code-comment, the lone comment
578 ;; will be used.  For example,
579 ;; @example
580 ;;   /* foo */
581 ;;   int x;
582 ;; @end example
583 ;; @noindent
584 ;; will be treated as if it was denereed
585 ;; @example
586 ;;   int x; /* foo */
587 ;; @end example
588 ;; @noindent
589 (define (fix-fields flds)
590   (let iter ((rz '()) (cl '()) (fl flds))
591     ;;(pretty-print fl)
592     (cond
593      ((null? fl) (reverse rz))
594      ((eqv? 'comment (caar fl))
595       (iter rz (cons (cadar fl) cl) (cdr fl)))
596      ((eqv? 'comp-decl (caar fl))
597       (if (eq? 4 (length (car fl)))
598           (iter (cons (car fl) rz) '() (cdr fl))         ; has comment
599           (let* ((cs (apply string-append (reverse cl))) ; add comment
600                  (fd (append (car fl) (list (list 'comment cs)))))
601             (iter (cons fd rz) '() (cdr fl)))))
602      (else
603       (error "bad field")))))
604
605 ;; --- last line ---