X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/239fa5bd3dff0b38b0cebdd3438311f21c24ba4f..6ac5b807942124461e19a7964165d7237c61fbb7:/src/c-types-parse.lisp diff --git a/src/c-types-parse.lisp b/src/c-types-parse.lisp index e3ac625..b398ca9 100644 --- a/src/c-types-parse.lisp +++ b/src/c-types-parse.lisp @@ -233,7 +233,7 @@ (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) @@ -290,7 +290,7 @@ ;;; `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 @@ -299,16 +299,16 @@ 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))))) @@ -336,13 +336,18 @@ (make-pointer-type type quals))) (cdr state)))))) - (next-declspec-p () - ;; Ansert whether the next token is a valid declaration - ;; specifier, without consuming it. - (and (eq (token-type scanner) :id) - (let ((id (token-value scanner))) - (or (gethash id *module-type-map*) - (gethash id *declspec-map*))))) + (predict-argument-list-p () + ;; See `prefix-lparen'. Predict an argument list rather + ;; than a nested declarator if (a) abstract declarators are + ;; permitted and (b) the next token is a declaration + ;; specifier or ellipsis. + (let ((type (token-type scanner)) + (value (token-value scanner))) + (and abstractp + (or (eq type :ellipsis) + (and (eq type :id) + (or (gethash value *module-type-map*) + (gethash value *declspec-map*))))))) (prefix-lparen () ;; Prefix: `(' @@ -357,25 +362,44 @@ ;; specifier, then we have a postfix argument list. (parse (peek (seq (#\( - (nil (if (and abstractp (next-declspec-p)) + (nil (if (predict-argument-list-p) (values nil nil nil) (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 `)' @@ -408,7 +432,7 @@ (parse (seq ((value (expr (:nestedp nestedp) ;; An actual operand. - (centre) + (kernel) ;; Binary operators. There aren't any. nil