* Comment Line-Up::
* Misc Line-Up::
+
Customizing Macros
* Macro Backslashes::
* Macros with ;::
+* Noise Macros::
@end detailmenu
@end menu
-
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@node Introduction, Overview, Top, Top
@comment node-name, next, previous, up
invoked @ccmode{} can only indent and fontify code heuristically.
Sometimes it gets it wrong. Usually you should try to design your
macros so that they ''look like ordinary code'' when you invoke them.
-However, one situation is so common that @ccmode{} handles it
+However, two situations are so common that @ccmode{} handles them
specially: that is when certain macros needn't (or mustn't) be
-followed by a @samp{;}. You need to configure @ccmode{} to handle
-these macros properly, see @ref{Macros with ;}.
+followed by a @samp{;}, and when certain macros (or compiler
+directives) expand to nothing. You need to configure @ccmode{} to
+handle these macros properly, see @ref{Macros with ;} and @ref{Noise
+Macros}.
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@menu
* Macro Backslashes::
* Macros with ;::
+* Noise Macros::
@end menu
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@end defopt
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-@node Macros with ;, , Macro Backslashes, Custom Macros
+@node Macros with ;, Noise Macros, Macro Backslashes, Custom Macros
@comment node-name, next, previous, up
@section Macros with semicolons
@cindex macros with semicolons
initialization code.
@end defun
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Noise Macros, , Macros with ;, Custom Macros
+@comment node-name, next, previous, up
+@section Noise Macros
+@cindex noise macros
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+In @ccmode{}, @dfn{noise macros} are macros which expand to nothing,
+or compiler directives (such as GCC's @code{__attribute__}) which play
+no part in the syntax of the C (etc.) language. Some noise macros are
+followed by arguments in parentheses (possibly optionally), others
+are not.
+
+Noise macros can easily confuse @ccmode{}'s analysis of function
+headers, causing them to be mis-fontified, or even mis-indented. You
+can prevent this confusion by specifying the identifiers which
+constitute noise macros.
+
+@defopt c-noise-macro-names
+@vindex noise-macro-names (c-)
+This variable is a list of names of noise macros which never have
+parenthesized arguments. Each element is a string, and must be a
+valid identifier. An element in @code{c-noise-macro-names} must not
+also be in @code{c-noise-macro-with-parens-names}. Such an element is
+treated as whitespace by @ccmode{}.
+@end defopt
+
+@defopt c-noise-macro-with-parens-names
+@vindex noise-macro-with-parens-names (c-)
+This variable is a list of names of noise macros which optionally have
+arguments in parentheses. Each element of the list is a string, and
+must be a valid identifier. An element in
+@code{c-noise-macro-with-parens-names} must not also be in
+@code{c-noise-macro-names}. For performance reasons, such an element,
+together with the optional parenthesized arguments, is specially
+handled, but it is only handled when used in declaration
+contexts@footnote{If this restriction causes your project
+difficulties, please get in touch with @email{bug-cc-mode@@gnu.org}.}.
+
+The two compiler directives @code{__attribute__} and @code{__declspec}
+have traditionally been handled specially in @ccmode{}; for example
+they are fontified with font-lock-keyword-face. You don't need to
+include these directives in @code{c-noise-macro-with-parens-names},
+but doing so is OK.
+@end defopt
+
+@defun c-make-noise-macro-regexps
+@findex make-noise-macro-regexps (c-)
+Call this (non-interactive) function, which sets internal variables,
+after changing the value of @code{c-noise-macro-names} or
+@code{c-noise-macro-with-parens-names} (e.g. in a hook (@pxref{CC
+Hooks})). This function is called by @ccmode{}'s initialization code.
+@end defun
+
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@node Odds and Ends, Sample Init File, Custom Macros, Top
@comment node-name, next, previous, up
;; two newlines with horizontal whitespace between them.
;;
;; The reason to include the first following char is to cope with
-;; "rung positions" that doesn't have any ordinary whitespace. If
+;; "rung positions" that don't have any ordinary whitespace. If
;; `c-is-sws' is put on a token character it does not have
;; `c-in-sws' set simultaneously. That's the only case when that
;; can occur, and the reason for not extending the `c-in-sws'
;; if it's anything that can't start syntactic ws, so we can bail out
;; early in the majority of cases when there just are a few ws chars.
(skip-chars-forward " \t\n\r\f\v")
- (when (looking-at c-syntactic-ws-start)
+ (when (or (looking-at c-syntactic-ws-start)
+ (and c-opt-cpp-prefix
+ (looking-at c-noise-macro-name-re)))
(setq rung-end-pos (min (1+ (point)) (point-max)))
(if (setq rung-is-marked (text-property-any rung-pos rung-end-pos
(with-silent-modifications
(while
(progn
+ ;; In the following while form, we move over a "ladder" and
+ ;; following simple WS each time round the loop, appending the WS
+ ;; onto the ladder, joining adjacent ladders, and terminating when
+ ;; there is no more WS or we reach EOB.
(while
(when (and rung-is-marked
(get-text-property (point) 'c-in-sws))
(setq rung-pos (point)
last-put-in-sws-pos rung-pos)))
+ ;; Now move over any comments (x)or a CPP construct.
(setq simple-ws-end (point))
(c-forward-comments)
(forward-line 1)
(setq safe-start t)
;; Don't cache at eob in case the buffer is narrowed.
+ (not (eobp)))
+
+ ((and c-opt-cpp-prefix
+ (looking-at c-noise-macro-name-re))
+ ;; Skip over a noise macro.
+ (goto-char (match-end 1))
+ (setq safe-start t)
(not (eobp)))))
;; We've searched over a piece of non-white syntactic ws. See if this
(when (and (not (bobp))
(save-excursion
(backward-char)
- (looking-at c-syntactic-ws-end)))
-
+ (or (looking-at c-syntactic-ws-end)
+ (and c-opt-cpp-prefix
+ (looking-at c-symbol-char-key)
+ (progn (c-beginning-of-current-token)
+ (looking-at c-noise-macro-name-re))))))
;; Try to find a rung position in the simple ws preceding point, so that
;; we can get a cache hit even if the last bit of the simple ws has
;; changed recently.
(with-silent-modifications
(while
(progn
+ ;; Each time round the next while form, we move back over a ladder
+ ;; and append any simple WS preceding it, if possible joining with
+ ;; the previous ladder.
(while
(when (and rung-is-marked
(not (bobp))
;; narrowed out, and we can't risk marking the simple ws
;; at the end of it.
(goto-char next-rung-pos)
+ t)
+
+ ((and c-opt-cpp-prefix
+ (save-excursion
+ (and (< (skip-syntax-backward "w_") 0)
+ (progn (setq next-rung-pos (point))
+ (looking-at c-noise-macro-name-re)))))
+ ;; Skipped over a noise macro
+ (goto-char next-rung-pos)
t)))
;; We've searched over a piece of non-white syntactic ws. See if this
`(c-forward-type)
`(c-forward-name)))
nil
- (and (looking-at c-keywords-regexp)
- (c-forward-keyword-clause 1))))
+ (cond ((looking-at c-keywords-regexp)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause)))))
(when (memq res '(t known found prefix))
,(when (eq type 'ref)
`(when c-record-type-identifiers
(c-forward-syntactic-ws)
(c-forward-keyword-prefixed-id ,type)))))
+(defun c-forward-noise-clause ()
+ ;; Point is at a c-noise-macro-with-parens-names macro identifier. Go
+ ;; forward over this name, any parenthesis expression which follows it, and
+ ;; any syntactic WS, ending up at the next token. If there is an unbalanced
+ ;; paren expression, leave point at it. Always Return t.
+ (c-forward-token-2)
+ (if (and (eq (char-after) ?\()
+ (c-go-list-forward))
+ (c-forward-syntactic-ws))
+ t)
+
(defun c-forward-keyword-clause (match)
;; Submatch MATCH in the current match data is assumed to surround a
;; token. If it's a keyword, move over it and any immediately
; "typedef".
(goto-char (match-end 1))
(c-forward-syntactic-ws)
+
+ (while (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
+
(setq pos (point))
(setq name-res (c-forward-name))
;; of the while. These are, e.g. "*" in "int *foo" or "(" and
;; "*" in "int (*foo) (void)" (Note similar code in
;; `c-forward-decl-or-cast-1'.)
- (while (and (looking-at c-type-decl-prefix-key)
- (if (and (c-major-mode-is 'c++-mode)
- (match-beginning 3))
- ;; If the third submatch matches in C++ then
- ;; we're looking at an identifier that's a
- ;; prefix only if it specifies a member pointer.
- (progn
- (setq id-start (point))
- (c-forward-name)
- (if (looking-at "\\(::\\)")
- ;; We only check for a trailing "::" and
- ;; let the "*" that should follow be
- ;; matched in the next round.
- t
- ;; It turned out to be the real identifier,
- ;; so flag that and stop.
- (setq got-identifier t)
- nil))
- t))
- (if (eq (char-after) ?\()
- (progn
- (setq paren-depth (1+ paren-depth))
- (forward-char))
- (goto-char (match-end 1)))
- (c-forward-syntactic-ws))
+ (while
+ (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))
+ ((and (looking-at c-type-decl-prefix-key)
+ (if (and (c-major-mode-is 'c++-mode)
+ (match-beginning 3))
+ ;; If the third submatch matches in C++ then
+ ;; we're looking at an identifier that's a
+ ;; prefix only if it specifies a member pointer.
+ (progn
+ (setq id-start (point))
+ (c-forward-name)
+ (if (looking-at "\\(::\\)")
+ ;; We only check for a trailing "::" and
+ ;; let the "*" that should follow be
+ ;; matched in the next round.
+ t
+ ;; It turned out to be the real identifier,
+ ;; so flag that and stop.
+ (setq got-identifier t)
+ nil))
+ t))
+ (if (eq (char-after) ?\()
+ (progn
+ (setq paren-depth (1+ paren-depth))
+ (forward-char))
+ (goto-char (match-end 1)))
+ (c-forward-syntactic-ws)
+ t)))
;; If we haven't passed the identifier already, do it now.
(unless got-identifier
;; Skip over any trailing bit, such as "__attribute__".
(progn
- (when (looking-at c-decl-hangon-key)
- (c-forward-keyword-clause 1))
- (<= (point) limit))
+ (while (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
+ (<= (point) limit))
;; Search syntactically to the end of the declarator (";",
;; ",", a closing paren, eob etc) or to the beginning of an
;; macros like __INLINE__, so we recognize both types and known
;; specifiers after them too.
(while
- (let* ((start (point)) kwd-sym kwd-clause-end found-type)
+ (let* ((start (point)) kwd-sym kwd-clause-end found-type noise-start)
+ (cond
;; Look for a specifier keyword clause.
- (when (or (looking-at c-prefix-spec-kwds-re) ;FIXME!!! includes auto
- (and (c-major-mode-is 'java-mode)
- (looking-at "@[A-Za-z0-9]+")))
- (if (save-match-data (looking-at c-typedef-key))
- (setq at-typedef t))
+ ((or (looking-at c-prefix-spec-kwds-re)
+ (and (c-major-mode-is 'java-mode)
+ (looking-at "@[A-Za-z0-9]+")))
+ (save-match-data
+ (if (looking-at c-typedef-key)
+ (setq at-typedef t)))
(setq kwd-sym (c-keyword-sym (match-string 1)))
(save-excursion
(c-forward-keyword-clause 1)
(setq kwd-clause-end (point))))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (setq noise-start (point))
+ (c-forward-noise-clause)
+ (setq kwd-clause-end (point))))
(when (setq found-type (c-forward-type t)) ; brace-block-too
;; Found a known or possible type or a prefix of a known type.
backup-at-type-decl nil
backup-maybe-typeless nil))
- (if kwd-sym
+ (if (or kwd-sym noise-start)
(progn
;; Handle known specifier keywords and
;; `c-decl-hangon-kwds' which can occur after known
;; types.
- (if (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
- ;; It's a hang-on keyword that can occur anywhere.
+ (if (or (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
+ noise-start)
+ ;; It's a hang-on keyword or noise clause that can occur
+ ;; anywhere.
(progn
- (setq at-decl-or-cast t)
(if at-type
;; Move the identifier start position if
;; we've passed a type.
;; If a known type was found, we still need to skip over any
;; hangon keyword clauses after it. Otherwise it has already
;; been done in the loop above.
- (while (looking-at c-decl-hangon-key)
- (c-forward-keyword-clause 1))
+ (while
+ (cond ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(setq id-start (point)))
((eq at-type 'prefix)
t)
((looking-at c-after-brace-list-key) t)
((looking-at c-brace-list-key) nil)
+ ((eq (char-after) ?\()
+ (and (eq (c-backward-token-2) 0)
+ (or (looking-at c-decl-hangon-key)
+ (looking-at c-noise-macro-with-parens-name-re))))
+
((and c-recognize-<>-arglists
(eq (char-after) ?<)
(looking-at "\\s("))
;; CASE 5A.3: brace list open
((save-excursion
(c-beginning-of-decl-1 lim)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws indent-point))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(setq placeholder (c-point 'boi))
(or (consp special-brace-list)
(and (or (save-excursion
(t
(save-excursion
(c-beginning-of-decl-1 lim)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws indent-point))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(c-add-syntax 'defun-open (c-point 'boi))
;; Bogus to use bol here, but it's the legacy. (Resolved,
;; 2007-11-09)
(c-beginning-of-statement-1
(c-safe-position (1- containing-sexp) paren-state))
(c-forward-token-2 0)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(c-add-syntax 'brace-list-open (c-point 'boi))))
;; CASE 9B: brace-list-close brace
:type 'c-extra-types-widget
:group 'c)
+(defvar c-noise-macro-with-parens-name-re nil)
+(defvar c-noise-macro-name-re nil)
+
+(defcustom c-noise-macro-names nil
+ "A list of names of macros which expand to nothing, or compiler extensions
+like \"????\" which are syntactic noise. Such a macro/extension is complete in
+itself, never having parentheses. All these names must be syntactically valid
+identifiers.
+
+If you change this variable's value, call the function
+`c-make-noise-macro-regexps' to set the necessary internal variables (or do
+this implicitly by reinitialising C/C++/Objc Mode on any buffer)."
+ :type '(repeat :tag "List of names" string)
+ :group 'c)
+
+(defcustom c-noise-macro-with-parens-names nil
+ "A list of names of macros \(or compiler extensions like \"__attribute__\")
+which optionally have arguments in parentheses, and which expand to nothing.
+These are recognized by CC Mode only in declarations."
+ :type '(regexp :tag "List of names (possibly empty)" string)
+ :group 'c)
+
+(defun c-make-noise-macro-regexps ()
+ ;; Convert `c-noise-macro-names' and `c-noise-macro-with-parens-names' into
+ ;; `c-noise-macro-name-re' and `c-noise-macro-with-parens-name-re'.
+ (setq c-noise-macro-with-parens-name-re
+ (cond ((null c-noise-macro-with-parens-names) "\\<\\>")
+ ((consp c-noise-macro-with-parens-names)
+ (concat (regexp-opt c-noise-macro-with-parens-names t)
+ "\\([^[:alnum:]_$]\\|$\\)"))
+ ((stringp c-noise-macro-with-parens-names)
+ (copy-sequence c-noise-macro-with-parens-names))
+ (t (error "c-make-noise-macro-regexps: \
+c-noise-macro-with-parens-names is invalid: %s" c-noise-macro-with-parens-names))))
+ (setq c-noise-macro-name-re
+ (cond ((null c-noise-macro-names) "\\<\\>")
+ ((consp c-noise-macro-names)
+ (concat (regexp-opt c-noise-macro-names t)
+ "\\([^[:alnum:]_$]\\|$\\)"))
+ ((stringp c-noise-macro-names)
+ (copy-sequence c-noise-macro-names))
+ (t (error "c-make-noise-macro-regexps: \
+c-noise-macro-names is invalid: %s" c-noise-macro-names)))))
\f
;; Non-customizable variables, still part of the interface to CC Mode
(defvar c-macro-with-semi-re nil