chiark / gitweb /
Massive reorganization in progress.
[sod] / src / parse-c-types.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Parser for C types
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensble Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Declaration specifiers.
30
31 (defclass declspec ()
32   ((label :type keyword :initarg :label :reader ds-label)
33    (name :type string :initarg :name :reader ds-name)
34    (kind :type (member type sign size qualifier tagged)
35          :initarg :kind :reader ds-kind)))
36
37 (defmethod shared-initialize :after ((ds declspec) slot-names &key)
38   (default-slot (ds 'name slot-names)
39     (string-downcase (ds-label ds))))
40
41 (defclass declspecs ()
42   ((type :initform nil :initarg :type :reader ds-type)
43    (sign :initform nil :initarg :sign :reader ds-sign)
44    (size :initform nil :initarg :size :reader ds-size)
45    (qualifier :initform nil :initarg :qualifiers :reader ds-qualifiers)))
46
47 (defparameter *declspec-map*
48   (let ((map (make-hash-table :test #'equal)))
49     (dolist (item '((type :void :char :int :float :double)
50                     (size :short :long (:long-long "long long"))
51                     (sign :signed :unsigned)
52                     (qualifier :const :restrict :volatile)
53                     (tagged :enum :struct :union)))
54       (let ((kind (car item)))
55         (dolist (spec (cdr item))
56           (multiple-value-bind (label name)
57               (if (consp spec)
58                   (values (car spec) (cadr spec))
59                   (values spec (string-downcase spec)))
60             (let ((ds (make-instance 'declspec
61                                      :label label :name name :kind kind)))
62               (setf (gethash name map) ds
63                     (gethash label map) ds))))))
64     map))
65
66 (defmethod ds-label ((ty c-type)) :c-type)
67 (defmethod ds-name ((ty c-type)) (princ-to-string ty))
68 (defmethod ds-kind ((ty c-type)) 'type)
69
70 (defparameter *good-declspecs*
71   '(((:int) (:signed :unsigned) (:short :long :long-long))
72     ((:char) (:signed :unsigned) ())
73     ((:double) () (:long))
74     (t () ()))
75   "List of good collections of declaration specifiers.
76
77    Each item is a list of the form (TYPES SIGNS SIZES).  Each of TYPES, SIGNS
78    and SIZES is either a list of acceptable specifiers of the appropriate
79    kind, or T, which matches any specifier.")
80
81 (defun scan-declspec (scanner)
82   "Scan a DECLSPEC from SCANNER.
83
84    Value on success is either a DECLSPEC object or a C-TYPE object."
85
86   ;; Turns out to be easier to do this by hand.
87   (let ((ds (and (eq (token-type scanner) :id)
88                  (let ((kw (token-value scanner)))
89                    (or (gethash kw *declspec-map*)
90                        (gethash kw *module-type-map*))))))
91     (cond ((not ds)
92            (values (list :declspec) nil nil))
93           ((eq (ds-kind ds) :tagged)
94            (scanner-step scanner)
95            (if (eq (token-type scanner) :id)
96                (let ((ty (make-c-tagged-type (ds-label ds)
97                                              (token-value scanner))))
98                  (scanner-step scanner)
99                  (values ty t t))
100                (values :tag nil t)))
101           (t
102            (scanner-step scanner)
103            (values ds t t)))))
104
105 (defun good-declspecs-p (specs)
106   "Are SPECS a good collection of declaration specifiers?"
107   (let ((speclist (list (ds-type specs) (ds-sign specs) (ds-size specs))))
108     (some (lambda (it)
109             (every (lambda (spec pat)
110                      (or (eq pat t) (null spec)
111                          (member (ds-label spec) pat)))
112                    speclist it))
113           *good-declspecs*)))
114
115 (defun combine-declspec (specs ds)
116   "Combine the declspec DS with the existing SPECS.
117
118    Returns new DECLSPECS if they're OK, or `nil' if not.  The old SPECS are
119    not modified."
120   (let* ((kind (ds-kind ds))
121          (old (slot-value specs kind)))
122     (multiple-value-bind (ok new)
123         (case kind
124           (qualifier (values t (adjoin ds old)))
125           (size (cond ((not old) (values t ds))
126                       ((and (eq (ds-label old) :long) (eq ds old))
127                        (values t (gethash :long-long *declspec-map*)))
128                       (t (values nil nil))))
129           (t (values (not old) ds)))
130       (if ok
131           (let ((copy (copy-instance specs)))
132             (setf (slot-value copy kind) new)
133             (and (good-declspecs-p copy) copy))
134           nil))))
135
136 (defun scan-and-merge-declspec (scanner specs)
137   (with-parser-context (token-scanner-context :scanner scanner)
138     (if-parse (:consumedp consumedp) (scan-declspec scanner)
139       (aif (combine-declspec specs it)
140            (values it t consumedp)
141            (values (list :declspec) nil consumedp)))))
142
143 (defun declspecs-type (specs)
144   (let ((type (ds-type specs))
145         (size (ds-size specs))
146         (sign (ds-sign specs)))
147     (cond ((or type size sign)
148            (when (and (eq (ds-label sign) :signed)
149                       (eq (ds-label type) :int))
150              (setf sign nil))
151            (cond ((and (or (null type) (eq (ds-label type) :int))
152                        (or size sign))
153                   (setf type nil))
154                  ((null type)
155                   (setf type (gethash :int *declspec-map*))))
156            (make-simple-type (format nil "~{~@[~A~^ ~]~}"
157                                      (mapcar #'ds-label
158                                              (remove nil
159                                                      (list sign size type))))
160                              (mapcar #'ds-label (ds-qualifiers specs))))
161           (t
162            nil))))
163
164 (defun parse-c-type (scanner)
165   (with-parser-context (token-scanner-context :scanner scanner)
166     (if-parse (:result specs :consumedp cp)
167               (many (specs (make-instance 'declspecs) it :min 1)
168                 (scan-and-merge-declspec scanner specs))
169               (let ((type (declspecs-type specs)))
170                 (if type (values type t cp)
171                     (values (list :declspec) nil cp))))))
172
173
174
175
176
177
178
179
180
181
182
183   ;; This is rather complicated, but extracting all the guts into a structure
184   ;; and passing it around makes matters worse rather than better.
185   ;;
186   ;; We categorize declaration specifiers into four kinds.
187   ;;
188   ;;   * `Type specifiers' describe the actual type, whether that's integer,
189   ;;     character, floating point, or some tagged or user-named type.
190   ;;
191   ;;   * `Size specifiers' distinguish different sizes of the same basic
192   ;;     type.  This is how we tell the difference between `int' and `long'.
193   ;;
194   ;;   * `Sign specifiers' distinguish different signednesses.  This is how
195   ;;     we tell the difference between `int' and `unsigned'.
196   ;;
197   ;;   * `Qualifiers' are our old friends `const', `restrict' and `volatile'.
198   ;;
199   ;; These groupings are for our benefit here, in determining whether a
200   ;; particular declaration specifier is valid in the current context.  We
201   ;; don't accept `function specifiers' (of which the only current example is
202   ;; `inline') since it's meaningless to us.
203   ;;
204   ;; Our basic strategy is to parse declaration specifiers while they're
205   ;; valid, and keep track of what we've read.  When we've reached the end,
206   ;; we'll convert what we've got into a `canonical form', and then convert
207   ;; that into a C type object of the appropriate kind.
208
209   (let ((specs (make-instance 'declspecs)))
210     
211
212   (let ((toks nil) (type nil) (size nil) (sign nil) (quals nil))
213     (labels ((goodp (ty sg sz)
214                "Are (TY SG SZ) a good set of declaration specifiers?"
215                (some (lambda (it)
216                        (every (lambda (spec pat)
217                                 (or (eq pat t) (eq spec nil)
218                                     (member spec pat)))
219                               decls it))
220                      *good-declspecs*))
221
222              (scan-declspec ()
223                "Scan a declaration specifier."
224                (flet ((win (value &optional (consumedp t))
225                         (when consumedp (scanner-step scanner))
226                         (return-from scan-declspec
227                           (values value t consumedp)))
228                       (lose (wanted &optional (consumedp nil))
229                         (values wanted nil consumedp)))
230                  (unless (eq (token-type scanner) :id) (lose :declspec))
231                  (let* ((id (token-value scanner))
232                         (ds (or (gethash id *declspec-map*)
233                                 (gethash id *module-type-map*))))
234                    (unless ds (lose :declspec))
235                    (let ((label (ds-label ds)))
236                      (ecase (ds-kind ds)
237                        (:qualifier
238                         (push (ds-label ds) quals)
239                         (win ds))
240                        (:size
241                         (cond ((and (not size) (goodp type label sign))
242                                (setf size label)
243                                (win ds))
244                               (t
245                                (lose :declspec))))
246                        (:sign
247                         (cond ((and (not sign) (goodp type size label))
248                                (setf sign label)
249                                (win ds))
250                               (t
251                                (lose :declspec))))
252                        (:type
253                         (when (and (eq type :long) (eq label :long))
254                           (setf label :long-long))
255                         (cond ((and (or (not type) (eq type :long))
256                                     (goodp label size sign))
257                                (setf type label)
258                                (win ds))
259                               (t
260                                (lose :declspec))))
261                        (:tagged
262                         (unless (and (not type) (goodp label size sign))
263                           (lose :declspec))
264                         (scanner-step scan)
265                         (unless (eq (token-type scanner) :id)
266                           (lose :tagged t))
267                         (setf type
268                               (make-c-tagged-type label
269                                                   (token-value scanner)))
270                         (win type))))))))
271
272       (with-parser-context (token-scanner-context :scanner scanner)
273         (many (nil nil nil :min 1)
274           (scan-declspec))
275
276
277
278
279   (let ((toks nil) (type nil) (size nil) (sign nil) (quals nil))
280     (labels ((check (ty sz sg)
281                (case ty
282                  ((nil :int) t)
283                  (:char (null sz))
284                  (:double (and (null sg) (or (null sz) (eq sz :long))))
285                  (t (and (null sg) (null sz)))))
286              (set-type (ty)
287                (when ))
288              (set-size (sz)
289                (when (and (eq sz :long) (eq size :long))
290                  (setf sz :long-long))
291                (when (and (or (null size) (eq sz :long-long))
292                           (check type sz sign))
293                  (setf size sz)))
294              (set-sign (sg)
295                (when (and (null sign) (check type size sg))
296                  (setf sign sg)))
297              (parse-declspec ()
298                (multiple-value-bind (kind value)
299                    (categorize-declspec scanner)
300                  (if (ecase kind
301                        (:qualifier (push value quals))
302                        (:type (and (null type) (check value size sign)
303                                    (setf type value)))
304                        (:size (let ((sz (if (and (eq size :long)
305                                                  (eq value :long))
306                                             :long-long value)))
307                                 (and (or (null size) (eq sz :long-long))
308                                      (check type value sign)
309                                      (setf size value))))
310                        (:sign (and (null sign) (check type size value)
311                                    (setf sign value)))
312                        
313
314 ;;;----- That's all, folks --------------------------------------------------