5 ;;; (c) 2009 Straylight/Edgeware
8 ;;;----- Licensing notice ---------------------------------------------------
10 ;;; This file is part of the Sensble Object Design, an object system for C.
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.
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.
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.
28 ;;;--------------------------------------------------------------------------
29 ;;; Declaration specifiers.
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)))
37 (defmethod shared-initialize :after ((ds declspec) slot-names &key)
38 (default-slot (ds 'name slot-names)
39 (string-downcase (ds-label ds))))
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)))
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)
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))))))
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)
70 (defparameter *good-declspecs*
71 '(((:int) (:signed :unsigned) (:short :long :long-long))
72 ((:char) (:signed :unsigned) ())
73 ((:double) () (:long))
75 "List of good collections of declaration specifiers.
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.")
81 (defun scan-declspec (scanner)
82 "Scan a DECLSPEC from SCANNER.
84 Value on success is either a DECLSPEC object or a C-TYPE object."
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*))))))
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)
100 (values :tag nil t)))
102 (scanner-step scanner)
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))))
109 (every (lambda (spec pat)
110 (or (eq pat t) (null spec)
111 (member (ds-label spec) pat)))
115 (defun combine-declspec (specs ds)
116 "Combine the declspec DS with the existing SPECS.
118 Returns new DECLSPECS if they're OK, or `nil' if not. The old SPECS are
120 (let* ((kind (ds-kind ds))
121 (old (slot-value specs kind)))
122 (multiple-value-bind (ok new)
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)))
131 (let ((copy (copy-instance specs)))
132 (setf (slot-value copy kind) new)
133 (and (good-declspecs-p copy) copy))
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)))))
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))
151 (cond ((and (or (null type) (eq (ds-label type) :int))
155 (setf type (gethash :int *declspec-map*))))
156 (make-simple-type (format nil "~{~@[~A~^ ~]~}"
159 (list sign size type))))
160 (mapcar #'ds-label (ds-qualifiers specs))))
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))))))
183 ;; This is rather complicated, but extracting all the guts into a structure
184 ;; and passing it around makes matters worse rather than better.
186 ;; We categorize declaration specifiers into four kinds.
188 ;; * `Type specifiers' describe the actual type, whether that's integer,
189 ;; character, floating point, or some tagged or user-named type.
191 ;; * `Size specifiers' distinguish different sizes of the same basic
192 ;; type. This is how we tell the difference between `int' and `long'.
194 ;; * `Sign specifiers' distinguish different signednesses. This is how
195 ;; we tell the difference between `int' and `unsigned'.
197 ;; * `Qualifiers' are our old friends `const', `restrict' and `volatile'.
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.
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.
209 (let ((specs (make-instance 'declspecs)))
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?"
216 (every (lambda (spec pat)
217 (or (eq pat t) (eq spec nil)
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)))
238 (push (ds-label ds) quals)
241 (cond ((and (not size) (goodp type label sign))
247 (cond ((and (not sign) (goodp type size label))
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))
262 (unless (and (not type) (goodp label size sign))
265 (unless (eq (token-type scanner) :id)
268 (make-c-tagged-type label
269 (token-value scanner)))
272 (with-parser-context (token-scanner-context :scanner scanner)
273 (many (nil nil nil :min 1)
279 (let ((toks nil) (type nil) (size nil) (sign nil) (quals nil))
280 (labels ((check (ty sz sg)
284 (:double (and (null sg) (or (null sz) (eq sz :long))))
285 (t (and (null sg) (null 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))
295 (when (and (null sign) (check type size sg))
298 (multiple-value-bind (kind value)
299 (categorize-declspec scanner)
301 (:qualifier (push value quals))
302 (:type (and (null type) (check value size sign)
304 (:size (let ((sz (if (and (eq size :long)
307 (and (or (null size) (eq sz :long-long))
308 (check type value sign)
310 (:sign (and (null sign) (check type size value)
314 ;;;----- That's all, folks --------------------------------------------------