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