nyacc: new release 0.75.5
[mes.git] / module / nyacc / lang / c99 / util2.scm
1 ;;; nyacc/lang/c99/util2.scm - C processing code
2 ;;; 
3 ;;; Copyright (C) 2015-2017 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 match-param-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 ;; TODO: add enums because they are global!!
179 ;; turn enum { ABC = 123 }; into '(ABC . (enum .. "ABC" "123" .. )
180 (define (match-decl decl seed)
181   (let* ((tag (sx-ref decl 0)) (attr (sx-attr decl)))
182     (case tag
183       ((decl)
184        (let* ((spec (sx-ref decl 1))    ; (decl-spec-list ...)
185               (tbd (sx-ref decl 2)))    ; (init-declr-list ...) OR ...
186          (cond
187           ((or (not tbd) (eqv? 'comment (sx-tag tbd)))
188            ;; no init-declr-list => struct or union def or param-decl enum
189            ;;(display "spec:\n") (pretty-print decl)
190            (sxml-match spec
191              ((decl-spec-list
192                (type-spec
193                 (struct-def (ident ,name) . ,rest2) . ,rest1))
194               (acons `(struct . ,name) decl seed))
195              ((decl-spec-list
196                (type-spec
197                 (union-def (ident ,name) . ,rest2) . ,rest1))
198               (acons `(union . ,name) decl seed))
199              ((decl-spec-list
200                (type-spec
201                 (enum-def
202                  (enum-def-list
203                   (enum-defn
204                    (ident "ABC")
205                    (p-expr (fixed "123")))))))
206               ;; TODO
207               seed)
208              (,otherwise
209               ;; e.g., enum { VAL = 1 };
210               ;;(simple-format #t "+++ otherwise: ~S\n" tbd) (pretty-print decl)
211               seed)))
212           (else ;; decl with init-declr-list
213            (let* ((id-l tbd) (tail (sx-tail decl 3)))
214              (let iter ((res seed) (idl (cdr id-l)))
215                (if (null? idl) res
216                    (let* ((declr (sx-ref (car idl) 1))
217                           (ident (declr->ident declr))
218                           (name (cadr ident)))
219                      (iter
220                       (acons name
221                              (if attr
222                                  (cons* tag attr spec (car idl) tail)
223                                  (cons* tag spec (car idl) tail))
224                              res)
225                       (cdr idl))))))))))
226       (else seed))))
227
228 ;; @deffn match-comp-decl decl seed
229 ;; This will turn
230 ;; @example
231 ;; (comp-decl (decl-spec-list (type-spec "int"))
232 ;;            (comp-decl-list
233 ;;             (comp-declr (ident "a")) (comp-declr (ident "b"))))
234 ;; @end example
235 ;; @noindent
236 ;; into
237 ;; @example
238 ;; ("a" . (comp-decl (decl-spec-list ...) (comp-declr (ident "a"))))
239 ;; ("b" . (comp-decl (decl-spec-list ...) (comp-declr (ident "b"))))
240 ;; @end example
241 ;; @noindent
242 ;; This is coded to be used with fold-right in order to preserve order
243 ;; in @code{struct} and @code{union} field lists.
244 (define (match-comp-decl decl seed)
245   (if (not (eqv? 'comp-decl (car decl))) seed
246       (let* ((tag (sx-ref decl 0))
247              (attr (sx-attr decl))
248              (spec (sx-ref decl 1))     ; (type-spec ...)
249              (id-l (sx-ref decl 2))     ; (init-declr-list ...)
250              (tail (sx-tail decl 3)))   ; opt comment, different here
251         ;;(simple-format #t "1: ~S\n" id-l)
252         (let iter ((res seed) (idl (cdr id-l)))
253           (if (null? idl) res
254               (let* ((declr (sx-ref (car idl) 1))
255                      (ident (declr->ident declr))
256                      (name (cadr ident)))
257                 ;;(pretty-print `(comp-decl ,spec ,(car idl) . ,tail))
258                 (acons name
259                        (if attr
260                            (cons* tag attr spec (car idl) tail)
261                            (cons* tag spec (car idl) tail))
262                        (iter res (cdr idl)))))))))
263
264 ;; @deffn match-param-decl param-decl seed
265 ;; This will turn
266 ;; @example
267 ;; (param-decl (decl-spec-list (type-spec "int")) (param-declr (ident "a")))
268 ;; @end example
269 ;; @noindent
270 ;; into
271 ;; @example
272 ;; ("a" . (comp-decl (decl-spec-list ...) (comp-declr (ident "a"))))
273 ;; @end example
274 ;; @noindent
275 ;; This is coded to be used with fold-right in order to preserve order
276 ;; in @code{struct} and @code{union} field lists.
277 (define (match-param-decl decl seed)
278   (if (not (eqv? 'param-decl (car decl))) seed
279       (let* ((tag (sx-ref decl 0))
280              (attr (sx-attr decl))
281              (spec (sx-ref decl 1))     ; (type-spec ...)
282              (declr (sx-ref decl 2))    ; (param-declr ...)
283              (ident (declr->ident declr))
284              (name (cadr ident)))
285         (acons name decl seed))))
286         
287 ;; @deffn find-special udecl-alist seed => ..
288 ;; NOT DONE
289 ;; @example
290 ;; '((struct . ("foo" ...) ...)
291 ;;   (union . ("bar" ...) ...)
292 ;;   (enum . ("bar" ...) ...)
293 ;;   seed)
294 ;; @end example
295 (define (find-special udecl-alist seed)
296   (let iter ((struct '()) (union '()) (enum '()) (udal udecl-alist))
297     (if (null? udal) (cons* (cons 'struct struct)
298                           (cons 'union union)
299                           (cons 'enum enum)
300                           seed)
301         '())))
302
303 (define tmap-fmt
304   '(("char" "%hhd")
305     ("unsigned char" "%hhu")
306     ("short int" "%hd")
307     ("unsigned short int" "%hu")
308     ("int" "%d")
309     ("unsigned int" "%u")
310     ("long int" "%ld")
311     ("unsigned long int" "%lu")
312     ("long long int" "%lld")
313     ("unsigned long long int" "%llu")))
314
315 (define fixed-width-int-names
316   '("int8_t" "uint8_t" "int16_t" "uint16_t"
317     "int32_t" "uint32_t" "int64_t" "uint64_t"))
318
319 ;; @deffn typedef-decl? decl)
320 (define (typedef-decl? decl)
321   (sxml-match decl
322     ((decl (decl-spec-list (stor-spec (typedef)) . ,r1) . ,r2) #t)
323     (,otherwise #f)))
324
325 ;; @deffn splice-declarators orig-declr tdef-declr => 
326 ;; Splice the original declarator into the typedef declarator.
327 ;; This is a helper for @code{expand-*-typename-ref} procecures.
328 (define (splice-declarators orig-declr tdef-declr)
329   
330   (define (fD seed tree)                ; => (values seed tree)
331     (sxml-match tree
332       ((param-list . ,rest) (values tree '())) ; don't process
333       ((ident ,name) (values (reverse (cadr orig-declr)) '())) ; replace
334       (,otherwise (values '() tree))))
335
336   (define (fU seed kseed tree)
337     (let ((ktree (case (car kseed)
338                    ((param-list ident) kseed)
339                    (else (reverse kseed)))))
340       (if (null? seed) ktree (cons ktree seed))))
341
342   (define (fH seed tree)
343     (cons tree seed))
344
345   ;; This cons transfers the tag from orig-declr to the result.
346   (cons
347    (car orig-declr)                     ; init-declr or comp-declr
348    (cdr (foldts* fD fU fH '() tdef-declr)))) ; always init-declr
349
350
351 ;; @deffn repl-typespec decl-spec-list replacement
352 ;; This is a helper for expand-decl-typerefs
353 (define (repl-typespec decl-spec-list replacement)
354   (fold-right
355    (lambda (item seed)
356      (cond ((symbol? item) (cons item seed))
357            ((eqv? 'type-spec (car item))
358             (if (pair? (car replacement))
359                 (append replacement seed)
360                 (cons replacement seed)))
361            (else (cons item seed))))
362    '() decl-spec-list))
363
364 ;; @deffn expand-decl-typerefs udecl udecl-dict => udecl
365 ;; Given a declaration or component-declaration, expand all typename,
366 ;; struct, union and enum refs.
367 ;; @example
368 ;; typedef const int  (*foo_t)(int a, double b);
369 ;; extern    foo_t    fctns[2];
370 ;; @noindent
371 ;; This routine should create an init-declarator associated with
372 ;; @end example
373 ;; extern {const int}  (*{fctns[2]})(int a, double b);
374 ;; @end example
375 ;; @noindent
376 ;; Cool. Eh? (but is it done?)
377 (define* (expand-decl-typerefs udecl udecl-dict #:key (keep '()))
378   (display "FIXME: some decls have no init-declr-list\n")
379   ;; between adding (init-declr-list) to those or having predicate
380   ;; (has-init-declr? decl)
381   (let* ((tag (sx-tag udecl))           ; decl or comp-decl
382          (attr (sx-attr udecl))         ; (@ ...)
383          (specl (sx-ref udecl 1))       ; decl-spec-list
384          (declr (or (sx-find 'init-declr udecl)
385                     (sx-find 'comp-declr udecl)))
386          (tail (if declr (sx-tail udecl 3) (sx-tail udecl 2))) ; opt comment
387          (tspec (cadr (sx-find 'type-spec specl))))
388     ;;(simple-format #t "=D> ~S\n" decl-spec-list)
389     ;;(simple-format #t "init-declr: ~S\n" init-declr)
390     (case (car tspec)
391       ((typename)
392        (cond
393         ((member (cadr tspec) keep)
394          udecl)
395         #;((member (cadr tspec) fixed-width-int-names)
396          ;; Convert it to @code{fixed-type}.
397          (let* ((name (cadr tspec))
398                 (fixd-tspec `(type-spec (fixed-type ,name)))
399                 (fixd-specl (repl-typespec specl fixd-tspec))
400                 ;; TODO add attr
401                 (fixed-udecl (cons* tag fixd-specl declr tail)))
402            ;;(expand-decl-typerefs fixed-udecl udecl-dict))) ; not needed ?
403            fixed-udecl))
404         (else
405          ;; splice in the typedef
406          (let* ((name (sx-ref tspec 1))
407                 (decl (assoc-ref udecl-dict name)) ; decl for typename
408                 (tdef-specl (sx-ref decl 1)) ; decl-spec-list for typename
409                 (tdef-declr (sx-ref decl 2)) ; init-declr for typename
410                 ;; splice the typedef specifiers into target:
411                 (fixd-specl (repl-typespec specl (sx-tail tdef-specl 2)))
412                 (fixd-declr (splice-declarators declr tdef-declr))
413                 (fixed-udecl (cons* tag fixd-specl fixd-declr tail)))
414            (expand-decl-typerefs fixed-udecl udecl-dict #:keep keep)))))
415
416       ((struct-ref union-ref)
417        (simple-format (current-error-port)
418                       "+++ c99/util2: struct/union-ref: more to do?\n")
419        ;;(simple-format #t "\nstruct-ref:\n") (pretty-print udecl)
420        udecl)
421
422       ((struct-def union-def)
423        (let* ((ident (sx-find 'ident tspec))
424               (field-list (sx-find 'field-list tspec))
425               (orig-flds (cdr field-list))
426               (unit-flds (map cdr (fold-right match-comp-decl '() orig-flds)))
427               (fixd-flds (map
428                           (lambda (fld)
429                             (expand-decl-typerefs fld udecl-dict #:keep keep))
430                           unit-flds))
431               (fixd-tspec
432                (if #f ;;ident
433                    `(type-spec (struct-def ,ident (field-list ,@fixd-flds)))
434                    `(type-spec (struct-def (field-list ,@fixd-flds)))))
435               (fixd-specl (repl-typespec specl fixd-tspec)))
436          (if declr (cons* tag fixd-specl declr tail)
437              (cons* tag fixd-specl tail))))
438       
439       ((enum-def)
440        (let* ((enum-def-list (sx-find 'enum-def-list tspec))
441               (fixd-def-list (canize-enum-def-list enum-def-list))
442               (fixd-tspec `(type-spec (enum-def ,fixd-def-list)))
443               (fixd-specl (repl-typespec specl fixd-tspec))
444               (fixed-decl (cons* tag fixd-specl declr tail))) ;; !!!
445          fixed-decl))
446
447       ((enum-ref)
448        (simple-format (current-error-port) "chack: enum-ref NOT DONE\n")
449        udecl)
450
451       (else udecl))))
452   
453 ;; @deffn canize-enum-def-list
454 ;; Fill in constants for all entries of an enum list.
455 (define (canize-enum-def-list enum-def-list)
456   (define (get-used edl)
457     (let iter ((uzd '()) (edl edl))
458          (cond
459           ((null? edl) uzd)
460           ((assq-ref (cdar edl) 'p-expr) =>
461            (lambda (x)
462              (iter (cons (string->number (cadar x)) uzd) (cdr edl))))
463           (else
464            (iter uzd (cdr edl))))))
465   (let ((used (get-used (cdr enum-def-list))))
466     (let iter ((rez '()) (ix 0) (edl (cdr enum-def-list)))
467       (cond
468        ((null? edl) (cons (car enum-def-list) (reverse rez)))
469        ((assq-ref (cdar edl) 'p-expr)
470         (iter (cons (car edl) rez) ix (cdr edl)))
471        (else
472         (let* ((ix1 (let iter ((ix (1+ ix)))
473                       (if (memq ix used) (iter (1+ ix)) ix)))
474                (is1 (number->string ix1)))
475           (iter (cons (append (car edl) `((p-expr (fixed ,is1)))) rez)
476                 ix1 (cdr edl))))))))
477
478 ;; @deffn stripdown udecl decl-dict => decl
479 ;; 1) remove stor-spec
480 ;; 2) expand typenames
481 ;; @example
482 ;; typedef int *x_t;
483 ;; x_t a[10];
484 ;; (spec (typename x_t)) (init-declr (array-of 10 (ident a)))
485 ;; (spec (typedef) (fixed-type "int")) (init-declr (pointer) (ident "x_t"))
486 ;; =>
487 ;; [TO BE DOCUMENTED]
488 ;; @end example
489 (define* (stripdown udecl decl-dict #:key (keep '()))
490
491   ;;(define strip-list '(stor-spec type-qual comment))
492   (define strip-list '(stor-spec type-qual))
493
494   (define (fsD seed tree)
495     '())
496
497   (define (fsU seed kseed tree)
498     (if (memq (car tree) strip-list)
499         seed
500         (if (null? seed)
501             (reverse kseed)
502             (cons (reverse kseed) seed))))
503         
504   (define (fsH seed tree)
505     (cons tree seed))
506
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 ;; This one experimental for guile ffi.
516 (define* (stripdown-2 udecl decl-dict #:key (keep '()))
517
518   ;;(define strip-list '(stor-spec type-qual comment))
519   (define strip-list '(stor-spec type-qual))
520
521   (define (fsD seed tree)
522     '())
523
524   (define (fsU seed kseed tree)
525     (if (memq (car tree) strip-list)
526         seed
527         (if (null? seed)
528             (reverse kseed)
529             (cons (reverse kseed) seed))))
530         
531   (define (fsH seed tree)
532     (cons tree seed))
533
534   (let* ((speclt (sx-tail udecl 1)))    ; decl-spec-list tail
535     ;; don't expand typedefs, structure specs etc,
536     (cond
537      ((and (eqv? 'stor-spec (caar speclt))
538            (eqv? 'typedef (cadar speclt)))
539       udecl)
540      ;; lone struct ref
541      (else
542       (let* ((xdecl (expand-decl-typerefs udecl decl-dict #:keep keep))
543              (tag (sx-tag xdecl))
544              (attr (sx-attr xdecl))
545              (specl (sx-ref xdecl 1))
546              (declr (sx-ref xdecl 2))
547              (specl1 (foldts fsD fsU fsH '() specl)))
548         (list tag specl1 declr))))
549       ))
550
551
552 ;; @deffn udecl->mspec sudecl
553 ;; Turn a stripped-down unit-declaration into an m-spec.
554 ;; This assumes decls have been run through @code{stripdown}.
555 (define (udecl->mspec decl . rest)
556
557   (define (cnvt-array-size size-spec)
558     (simple-format #t "cnvt-array-size\n")
559     (with-output-to-string (lambda () (pretty-print-c99 size-spec))))
560
561   (define (unwrap-specl specl)
562     (let ((tspec (cadadr specl)))
563       ;;(simple-format #t "tspec:\n") (pretty-print tspec)
564       (sxml-match tspec
565         ((xxx-struct-def (field-list . ,rest))
566          `(struct-def ,@rest))
567         (,otherwise
568          tspec))))
569     
570   (define (unwrap-declr declr)
571     (sxml-match declr
572       ((ident ,name)
573        (list name))
574       ((init-declr ,item)
575        (unwrap-declr item))
576       ((comp-declr ,item)
577        (unwrap-declr item))
578       ((ptr-declr (pointer . ,r) ,dir-declr)
579        (cons '(pointer-to) (unwrap-declr dir-declr)))
580       ((array-of ,dir-declr ,size)
581        (cons `(array-of ,(cnvt-array-size size)) (unwrap-declr dir-declr)))
582       ((ftn-declr ,dir-declr ,params)
583        (cons '(function-returning) (unwrap-declr dir-declr)))
584       ((scope ,expr)
585        (unwrap-declr expr))
586       (,otherwise
587        (simple-format #t "unwrap-declr: OTHERWISE\n") (pretty-print otherwise)
588        ;; failed got: (array-of (ident "foo")) FROM const char foo[];
589        #f)))
590
591   (define (find-type-spec decl-spec-list)
592     (let iter ((tsl (cdr decl-spec-list)))
593       (if (eqv? 'type-spec (caar tsl)) (car tsl)
594           (iter (cdr tsl))))) 
595   
596   (let* ((decl-dict (if (pair? rest) (car rest) '()))
597          (specl (sx-ref decl 1))
598          (declr (sx-ref decl 2))
599          (comm (sx-ref decl 3))
600          (m-specl (unwrap-specl specl))
601          (m-declr (unwrap-declr declr))
602          (m-decl (reverse (cons m-specl m-declr))))
603     m-decl))
604
605 (define* (udecl->mspec/comm decl #:optional (dict '()) #:key (def-comm ""))
606   (let* ((comm (sx-ref decl 3))
607          (spec (udecl->mspec decl dict)))
608     (cons* (car spec) (or comm `(comment ,def-comm)) (cdr spec))))
609
610 ;; @deffn fix-fields flds => flds
611 ;; This will take a list of fields from a struct and remove lone comments.
612 ;; If a field following a lone comment has no code-comment, the lone comment
613 ;; will be used.  For example,
614 ;; @example
615 ;;   /* foo */
616 ;;   int x;
617 ;; @end example
618 ;; @noindent
619 ;; will be treated as if it was denereed
620 ;; @example
621 ;;   int x; /* foo */
622 ;; @end example
623 ;; @noindent
624 (define (fix-fields flds)
625   (let iter ((rz '()) (cl '()) (fl flds))
626     ;;(pretty-print fl)
627     (cond
628      ((null? fl) (reverse rz))
629      ((eqv? 'comment (caar fl))
630       (iter rz (cons (cadar fl) cl) (cdr fl)))
631      ((eqv? 'comp-decl (caar fl))
632       (if (eq? 4 (length (car fl)))
633           (iter (cons (car fl) rz) '() (cdr fl))         ; has comment
634           (let* ((cs (apply string-append (reverse cl))) ; add comment
635                  (fd (append (car fl) (list (list 'comment cs)))))
636             (iter (cons fd rz) '() (cdr fl)))))
637      (else
638       (error "bad field")))))
639
640 ;; --- last line ---