- (labels ((qualifiers ()
- ;; QUALIFIER*
-
- (parse
- (seq ((quals (list ()
- (scan-declspec
- scanner
- :indicator :qualifier
- :predicate (lambda (ds)
- (and (typep ds 'declspec)
- (eq (ds-kind ds)
- 'qualifier)))))))
- (mapcar #'ds-label quals))))
-
- (star ()
- ;; Prefix: `*' QUALIFIERS
-
- (parse (seq (#\* (quals (qualifiers)))
- (preop "*" (state 9)
- (cons (lambda (type)
- (funcall (car state)
- (make-pointer-type type quals)))
- (cdr state))))))
-
- (prefix-lparen ()
- ;; Prefix: `('
- ;;
- ;; Opening parentheses are treated as prefix operators by the
- ;; expression parsing engine. There's an annoying ambiguity
- ;; in the syntax if abstract declarators are permitted: a `('
- ;; might be either the start of a nested subdeclarator or the
- ;; start of a postfix function argument list. The two are
- ;; disambiguated by stating that if the token following the
- ;; `(' is a `)' or a declaration specifier, then we have a
- ;; postfix argument list.
-
- (parse
- (peek (seq (#\(
- (nil (if (and abstractp
- (eq (token-type scanner) :id)
- (let ((id (token-value scanner)))
- (or (gethash id
- *module-type-map*)
- (gethash id
- *declspec-map*))))
- (values nil nil nil)
- (values t t nil))))
- (lparen #\))))))
-
- (centre ()
- ;; ID | empty
- ;;
- ;; The centre might be empty or contain an identifier,
- ;; depending on the setting of ABSTRACTP.
-
- (parse (or (when (not (eq abstractp t))
- (seq ((id :id)) (cons #'identity id)))
- (when abstractp
- (t (cons #'identity nil))))))
-
- (argument-list ()
- ;; [ ARGUMENT [ `,' ARGUMENT ]* ]
-
- (parse (list ()
- (seq ((base-type (parse-c-type scanner))
- (dtor (parse-declarator scanner
- base-type
- :abstractp :maybe)))
- (make-argument (cdr dtor) (car dtor)))
- #\,)))
-
- (postfix-lparen ()
- ;; Postfix: `(' ARGUMENT-LIST `)'
-
- (parse (seq (#\( (args (argument-list)) #\))
- (postop "()" (state 9)
- (cons (lambda (type)
- (funcall (car state)
- (make-function-type type args)))
- (cdr state))))))
-
- (dimension ()
- ;; `[' C-FRAGMENT ']'
-
- (parse-delimited-fragment scanner #\[ #\]))
-
- (lbracket ()
- ;; Postfix: DIMENSION+
-
- (parse (seq ((dims (list (:min 1) (dimension))))
- (postop "[]" (state 10)
- (cons (lambda (type)
- (funcall (car state)
- (make-array-type type dims)))
- (cdr state)))))))
-
- ;; And now we actually do the declarator parsing.
- (parse (seq ((value (expr (:nestedp nestedp)
-
- ;; An actual operand.
- (centre)
-
- ;; Binary operators. There aren't any.
- nil
-
- ;; Prefix operators.
- (or (star)
- (prefix-lparen))
-
- ;; Postfix operators.
- (or (postfix-lparen)
- (lbracket)
- (when nestedp (seq (#\)) (rparen #\))))))))
- (cons (funcall (car value) base-type) (cdr value)))))))
+ (with-parser-context (token-scanner-context :scanner scanner)
+ (let ((kernel-parser (cond (kernel kernel)
+ (abstractp (parser () (? :id)))
+ (t (parser () :id)))))
+
+ (labels ((qualifiers ()
+ ;; qualifier*
+
+ (parse
+ (seq ((quals (list ()
+ (scan-simple-declspec
+ scanner
+ :indicator :qualifier
+ :predicate (lambda (ds)
+ (and (typep ds 'declspec)
+ (eq (ds-kind ds)
+ 'qualifier)))))))
+ (mapcar #'ds-label quals))))
+
+ (disallow-keyword-functions (type)
+ (when (typep type 'c-keyword-function-type)
+ (error "Functions with keyword arguments are only ~
+ allowed at top-level")))
+
+ (star ()
+ ;; Prefix: `*' qualifiers
+
+ (parse (seq (#\* (quals (qualifiers)))
+ (preop "*" (state 9)
+ (cons (lambda (type)
+ (disallow-keyword-functions type)
+ (funcall (car state)
+ (make-pointer-type type quals)))
+ (cdr state))))))
+
+ (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: `('
+ ;;
+ ;; Opening parentheses are treated as prefix operators by
+ ;; the expression parsing engine. There's an annoying
+ ;; ambiguity in the syntax if abstract declarators are
+ ;; permitted: a `(' might be either the start of a nested
+ ;; subdeclarator or the start of a postfix function argument
+ ;; list. The two are disambiguated by stating that if the
+ ;; token following the `(' is a `)' or a declaration
+ ;; specifier, then we have a postfix argument list.
+ (parse
+ (peek (seq (#\(
+ (nil (if (predict-argument-list-p)
+ (values nil nil nil)
+ (values t t nil))))
+ (lparen #\))))))
+
+ (kernel ()
+ (parse (seq ((name (funcall kernel-parser)))
+ (cons #'identity name))))
+
+ (arg-decl (abstractp)
+ (parse (seq ((base-type (parse-c-type scanner))
+ (dtor (parse-declarator scanner base-type
+ :abstractp abstractp)))
+ dtor)))
+
+ (argument ()
+ ;; argument ::= type abstract-declspec
+
+ (parse (seq ((dtor (arg-decl t)))
+ (make-argument (cdr dtor) (car dtor)))))
+
+ (kw-argument ()
+ ;; kw-argument ::= type declspec [= c-fragment]
+
+ (parse (seq ((dtor (arg-decl nil))
+ (dflt (? (when (eq (token-type scanner) #\=)
+ (parse-delimited-fragment
+ scanner #\= '(#\, #\))
+ :keep-end t)))))
+ (make-argument (cdr dtor) (car dtor) dflt))))
+
+ (argument-list ()
+ ;; argument-list ::=
+ ;; [argument [`,' argument]* [`,' argument-tail]]
+ ;; | argument-tail
+ ;;
+ ;; argument-tail ::= `...' | keyword-tail
+ ;;
+ ;; keyword-tail ::= `?' [kw-argument [`,' kw-argument]*]
+ ;;
+ ;; kw-argument ::= argument [= c-fragment]
+ ;;
+ ;; 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)
+ (keys nil)
+ (keysp nil))
+ (loop
+ (when (eq (token-type scanner) :ellipsis)
+ (push :ellipsis args)
+ (scanner-step scanner)
+ (return))
+ (when (and keywordp (eq (token-type scanner) #\?))
+ (setf keysp t)
+ (scanner-step scanner)
+ (multiple-value-bind (arg winp consumedp)
+ (parse (list (:min 0) (kw-argument) #\,))
+ (declare (ignore consumedp))
+ (unless winp
+ (return-from argument-list (values arg nil t)))
+ (setf keys arg)
+ (return)))
+ (multiple-value-bind (arg winp consumedp)
+ (argument)
+ (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 (let ((rargs (nreverse args))
+ (rkeys (nreverse keys)))
+ (if keysp
+ (lambda (ret)
+ (make-keyword-function-type
+ ret rargs rkeys))
+ (lambda (ret)
+ (make-function-type ret rargs))))
+ t
+ (or args keysp))))
+
+ (postfix-lparen ()
+ ;; Postfix: `(' argument-list `)'
+
+ (parse (seq (#\( (make (argument-list)) #\))
+ (postop "()" (state 10)
+ (cons (lambda (type)
+ (disallow-keyword-functions type)
+ (funcall (car state)
+ (funcall make type)))
+ (cdr state))))))
+
+ (dimension ()
+ ;; `[' c-fragment ']'
+
+ (parse (seq ((frag (parse-delimited-fragment
+ scanner #\[ #\])))
+ (c-fragment-text frag))))
+
+ (lbracket ()
+ ;; Postfix: dimension+
+
+ (parse (seq ((dims (list (:min 1) (dimension))))
+ (postop "[]" (state 10)
+ (cons (lambda (type)
+ (disallow-keyword-functions type)
+ (funcall (car state)
+ (make-array-type type dims)))
+ (cdr state)))))))
+
+ ;; And now we actually do the declarator parsing.
+ (parse (seq ((value (expr (:nestedp nestedp)
+
+ ;; An actual operand.
+ (kernel)
+
+ ;; Binary operators. There aren't any.
+ nil
+
+ ;; Prefix operators.
+ (or (star)
+ (prefix-lparen))
+
+ ;; Postfix operators.
+ (or (postfix-lparen)
+ (lbracket)
+ (when nestedp (seq (#\)) (rparen #\))))))))
+ (cons (wrap-c-type (lambda (type)
+ (funcall (car value) type))
+ base-type)
+ (cdr value))))))))