src/c-types-parse.lisp: Plain types don't have `declspec' slots.
[sod] / src / c-types-parse.lisp
index e3ac625..e0cfc88 100644 (file)
                       (gethash kw *declspec-map*))))))
     (cond ((or (not ds) (and predicate (not (funcall predicate ds))))
           (values (list indicator) nil nil))
-         ((ds-taggedp ds)
+         ((and (typep ds 'declspec) (ds-taggedp ds))
           (scanner-step scanner)
           (if (eq (token-type scanner) :id)
               (let ((ty (make-c-tagged-type (ds-label ds)
 ;;; `parse-declarator' will be of this form.
 
 (export 'parse-declarator)
-(defun parse-declarator (scanner base-type &key centre abstractp)
+(defun parse-declarator (scanner base-type &key kernel abstractp)
   "Parse a C declarator, returning a pair (C-TYPE . NAME).
 
    The SCANNER is a token scanner to read from.  The BASE-TYPE is the type
 
    The result contains both the resulting constructed C-TYPE (with any
    qualifiers etc. as necessary), and the name from the middle of the
-   declarator.  The name is parsed using the CENTRE parser provided, and
+   declarator.  The name is parsed using the KERNEL parser provided, and
    defaults to matching a simple identifier `:id'.  This might, e.g., be
    (? :id) to parse an `abstract declarator' which has optional names.
 
-   There's an annoying ambiguity in the syntax, if an empty CENTRE is
+   There's an annoying ambiguity in the syntax, if an empty KERNEL is
    permitted.  In this case, you must ensure that ABSTRACTP is true so that
    the appropriate heuristic can be applied.  As a convenience, if ABSTRACTP
-   is true then `(? :id)' is used as the default CENTRE."
+   is true then `(? :id)' is used as the default KERNEL."
   (with-parser-context (token-scanner-context :scanner scanner)
-    (let ((centre-parser (cond (centre centre)
+    (let ((kernel-parser (cond (kernel kernel)
                               (abstractp (parser () (? :id)))
                               (t (parser () :id)))))
 
                                        (values t t nil))))
                           (lparen #\))))))
 
-              (centre ()
-                (parse (seq ((name (funcall centre-parser)))
+              (kernel ()
+                (parse (seq ((name (funcall kernel-parser)))
                          (cons #'identity name))))
 
               (argument-list ()
-                ;; [ argument [ `,' argument ]* ]
-
-                (parse (list ()
-                             (seq ((base-type (parse-c-type scanner))
-                                   (dtor (parse-declarator scanner
-                                                           base-type
-                                                           :abstractp t)))
-                               (make-argument (cdr dtor) (car dtor)))
-                             #\,)))
+                ;; [ argument [ `,' argument ]* [ `,' `...' ] ] | `...'
+                ;;
+                ;; The possibility of a trailing `,' `...' means that we
+                ;; can't use the standard `list' parser.  Note that, unlike
+                ;; `real' C, we allow an ellipsis even if there are no
+                ;; explicit arguments.
+
+                (let ((args nil))
+                  (loop
+                    (when (eq (token-type scanner) :ellipsis)
+                      (push :ellipsis args)
+                      (scanner-step scanner)
+                      (return))
+                    (multiple-value-bind (arg winp consumedp)
+                        (parse (seq ((base-type (parse-c-type scanner))
+                                     (dtor (parse-declarator scanner
+                                                             base-type
+                                                             :abstractp t)))
+                                 (make-argument (cdr dtor) (car dtor))))
+                      (unless winp
+                        (if (or consumedp args)
+                            (return-from argument-list (values arg nil t))
+                            (return)))
+                      (push arg args))
+                    (unless (eq (token-type scanner) #\,)
+                      (return))
+                    (scanner-step scanner))
+                  (values (nreverse args) t args)))
 
               (postfix-lparen ()
                 ;; Postfix: `(' argument-list `)'
        (parse (seq ((value (expr (:nestedp nestedp)
 
                              ;; An actual operand.
-                             (centre)
+                             (kernel)
 
                              ;; Binary operators.  There aren't any.
                              nil