Parse an external declaration.
(parse-external-declaration parstate) → (mv erp extdecl span new-parstate)
An external declaration is
either an empty one (a lone semicolon),
or a function definition,
which starts with a non-empty sequence of declaration specifiers,
or a declaration,
which also starts with a non-empty sequence of declaration specifiers,
unless it is a static assert declaration,
which starts with the keyword
The case of an empty external declaration is easy, because it starts (and ends) with a semicolon. This is only allowed if GCC extensions are supported.
No declaration specifier starts with the keyword
Otherwise, we read one or more declaration specifiers, since those are present both in declarations and in function definitions. Then we must have a declarator in either case, but based on what follows it, we can decide whether we have a declarator or a function definition.
If GCC extensions are supported, we must also take into account
the possible presence of attributes and assembler name specifiers,
as well as of an
We also handle the GCC extension of allowing assembler statements as external declarations, which are easy to recognize.
Function:
(defun parse-external-declaration (parstate) (declare (xargs :stobjs (parstate))) (declare (xargs :guard (parstatep parstate))) (let ((__function__ 'parse-external-declaration)) (declare (ignorable __function__)) (b* (((reterr) (irr-ext-declon) (irr-span) parstate) ((erp token span parstate) (read-token parstate))) (cond ((and (token-punctuatorp token ";") (parstate->gcc parstate)) (retok (ext-declon-empty) span parstate)) ((token-keywordp token "_Static_assert") (b* (((erp statassert span parstate) (parse-static-assert-declaration span parstate))) (retok (ext-declon-declon (declon-statassert statassert)) span parstate))) ((or (token-keywordp token "asm") (token-keywordp token "__asm") (token-keywordp token "__asm__")) (b* ((uscores (cond ((token-keywordp token "asm") (keyword-uscores-none)) ((token-keywordp token "__asm") (keyword-uscores-start)) ((token-keywordp token "__asm__") (keyword-uscores-both)))) ((erp asm span parstate) (parse-asm-statement span uscores parstate))) (retok (ext-declon-asm asm) span parstate))) (t (b* (((mv extension parstate) (if (token-keywordp token "__extension__") (mv t parstate) (b* ((parstate (if token (unread-token parstate) parstate))) (mv nil parstate)))) ((erp declspecs span parstate) (parse-declaration-specifiers nil parstate)) ((erp token2 span2 parstate) (read-token parstate))) (cond ((token-punctuatorp token2 ";") (retok (ext-declon-declon (make-declon-declon :extension extension :specs declspecs :declors nil)) (span-join span span2) parstate)) (t (b* ((parstate (if token2 (unread-token parstate) parstate)) ((erp declor & parstate) (parse-declarator parstate)) ((erp asmspec? & parstate) (parse-?-asm-name-specifier parstate)) ((erp attrspecs & parstate) (parse-*-attribute-specifier parstate)) ((erp token3 span3 parstate) (read-token parstate))) (cond ((token-punctuatorp token3 ";") (retok (ext-declon-declon (make-declon-declon :extension extension :specs declspecs :declors (list (make-init-declor :declor declor :asm? asmspec? :attribs attrspecs :initer? nil :info nil)))) (span-join span span3) parstate)) ((token-punctuatorp token3 "=") (b* (((erp initer & parstate) (parse-initializer parstate)) (initdeclor (make-init-declor :declor declor :asm? asmspec? :attribs attrspecs :initer? initer :info nil)) ((erp token4 span4 parstate) (read-token parstate))) (cond ((token-punctuatorp token4 ";") (retok (ext-declon-declon (make-declon-declon :extension extension :specs declspecs :declors (list initdeclor))) (span-join span span4) parstate)) ((token-punctuatorp token4 ",") (b* (((erp initdeclors & parstate) (parse-init-declarator-list parstate)) ((erp last-span parstate) (read-punctuator ";" parstate))) (retok (ext-declon-declon (make-declon-declon :extension extension :specs declspecs :declors (cons initdeclor initdeclors))) (span-join span last-span) parstate))) (t (reterr-msg :where (position-to-msg (span->start span4)) :expected "a semicolon or a comma" :found (token-to-msg token4)))))) ((token-punctuatorp token3 ",") (b* ((initdeclor (make-init-declor :declor declor :asm? asmspec? :attribs attrspecs :initer? nil :info nil)) ((erp initdeclors & parstate) (parse-init-declarator-list parstate)) ((erp last-span parstate) (read-punctuator ";" parstate))) (retok (ext-declon-declon (make-declon-declon :extension extension :specs declspecs :declors (cons initdeclor initdeclors))) (span-join span last-span) parstate))) ((token-punctuatorp token3 "{") (b* (((erp cstmt last-span parstate) (parse-compound-statement span parstate))) (retok (ext-declon-fundef (make-fundef :extension extension :specs declspecs :declor declor :asm? asmspec? :attribs attrspecs :declons nil :body cstmt :info nil)) (span-join span last-span) parstate))) (t (b* ((parstate (if token3 (unread-token parstate) parstate)) ((erp decls & parstate) (parse-declaration-list parstate)) ((erp open-curly-span parstate) (read-punctuator "{" parstate)) ((erp cstmt last-span parstate) (parse-compound-statement open-curly-span parstate))) (retok (ext-declon-fundef (make-fundef :extension extension :specs declspecs :declor declor :asm? asmspec? :attribs attrspecs :declons decls :body cstmt :info nil)) (span-join span last-span) parstate)))))))))))))
Theorem:
(defthm ext-declonp-of-parse-external-declaration.extdecl (b* (((mv acl2::?erp ?extdecl ?span ?new-parstate) (parse-external-declaration parstate))) (ext-declonp extdecl)) :rule-classes :rewrite)
Theorem:
(defthm spanp-of-parse-external-declaration.span (b* (((mv acl2::?erp ?extdecl ?span ?new-parstate) (parse-external-declaration parstate))) (spanp span)) :rule-classes :rewrite)
Theorem:
(defthm parstatep-of-parse-external-declaration.new-parstate (implies (parstatep parstate) (b* (((mv acl2::?erp ?extdecl ?span ?new-parstate) (parse-external-declaration parstate))) (parstatep new-parstate))) :rule-classes :rewrite)
Theorem:
(defthm parsize-of-parse-external-declaration-uncond (b* (((mv acl2::?erp ?extdecl ?span ?new-parstate) (parse-external-declaration parstate))) (<= (parsize new-parstate) (parsize parstate))) :rule-classes :linear)
Theorem:
(defthm parsize-of-parse-external-declaration-cond (b* (((mv acl2::?erp ?extdecl ?span ?new-parstate) (parse-external-declaration parstate))) (implies (not erp) (<= (parsize new-parstate) (1- (parsize parstate))))) :rule-classes :linear)