Massive reorganization in progress.
[sod] / src / parse-c-types.lisp
CommitLineData
dea4d055
MW
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 --------------------------------------------------