From 536610a433e6edc0b3f831272c4e0424ebebee46 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Thu, 27 Oct 2011 20:34:23 +0000 Subject: [PATCH] Amend to indent and fontify macros "which include their own semicolon" correctly, using the "virtual semicolon" mechanism. cc-defs.el: Update "virtual semicolon" comments. cc-engine.el (c-crosses-statement-barrier-p): Recoded to scan one line at at time rather than having \n and \r explicitly in c-stmt-delim-chars (for some modes, e.g. AWK). (c-forward-label): Amend for virtual semicolons. (c-at-macro-vsemi-p, c-macro-vsemi-status-unknown-p): New functions cc-fonts.el (c-font-lock-declarations): Take account of the new C macros. cc-langs.el (c-at-vsemi-p-fn, c-vsemi-status-unknown-p-fn): move to earlier in the file. (c-opt-cpp-symbol, c-line-comment-start-regexp): New language variables. (c-opt-cpp-macro-define): Make into a full language variable. (c-stmt-delim-chars, c-stmt-delim-chars-with-comma): Special value for AWK Mode (including \n, \r) removed, no longer needed. cc-mode.el (c-mode, c++-mode, objc-mode): Invoke c-make-macro-with-semi-re. cc-vars.el (c-macro-with-semi-re, c-macro-names-with-semicolon): New variables. (c-make-macro-with-semi-re): New function cc-mode.texi (Indentation Commands): Mention "macros with semicolons". (Other Special Indentations): Add an xref to "Macros with ;". (Customizing Macros): Add stuff about syntax in macros. Add an xref to "Macros with ;". (Macros with ;): New page. --- doc/misc/cc-mode.texi | 97 +++++++++++++++++++++++ lisp/progmodes/cc-defs.el | 19 ++--- lisp/progmodes/cc-engine.el | 150 +++++++++++++++++++++++++++--------- lisp/progmodes/cc-fonts.el | 8 +- lisp/progmodes/cc-langs.el | 72 ++++++++++------- lisp/progmodes/cc-mode.el | 3 + lisp/progmodes/cc-vars.el | 48 ++++++++++++ 7 files changed, 320 insertions(+), 77 deletions(-) diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi index a9339162666..4cc7f351c2e 100644 --- a/doc/misc/cc-mode.texi +++ b/doc/misc/cc-mode.texi @@ -341,6 +341,11 @@ Line-Up Functions * Comment Line-Up:: * Misc Line-Up:: +Customizing Macros + +* Macro Backslashes:: +* Macros with ;:: + @end detailmenu @end menu @@ -655,6 +660,10 @@ expression, to some statements, or perhaps to whole functions, the syntactic recognition can be wrong. @ccmode{} manages to figure it out correctly most of the time, though. +Some macros, when invoked, ''have their own semicolon''. To get the +next line indented correctly, rather than as a continuation line, +@xref{Macros with ;}. + Reindenting large sections of code can take a long time. When @ccmode{} reindents a region of code, it is essentially equivalent to hitting @key{TAB} on every line of the region. @@ -6550,6 +6559,9 @@ custom line-up function associated with it. @section Other Special Indentations @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +To configure macros which you invoke without a terminating @samp{;}, +see @xref{Macros with ;}. + Here are the remaining odds and ends regarding indentation: @defopt c-label-minimum-indentation @@ -6601,6 +6613,13 @@ functions to this hook, not remove them. @xref{Style Variables}. @cindex preprocessor directives @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Preprocessor macros in C, C++, and Objective C (introduced by +@code{#define}) have a syntax different from the main language---for +example, a macro declaration is not terminated by a semicolon, and if +it is more than a line long, line breaks in it must be escaped with +backslashes. @ccmode{} has some commands to manipulate these, see +@ref{Macro Backslashes}. + Normally, the lines in a multi-line macro are indented relative to each other as though they were code. You can suppress this behavior by setting the following user option: @@ -6612,6 +6631,28 @@ is @code{nil}, all lines inside macro definitions are analyzed as @code{cpp-macro-cont}. @end defopt +Because a macro can expand into anything at all, near where one is +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 +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 ;}. + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@menu +* Macro Backslashes:: +* Macros with ;:: +@end menu + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Macro Backslashes, Macros with ;, Custom Macros, Custom Macros +@comment node-name, next, previous, up +@section Customizing Macro Backslashes +@cindex #define +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + @ccmode{} provides some tools to help keep the line continuation backslashes in macros neat and tidy. Their precise action is customized with these variables: @@ -6653,6 +6694,62 @@ get aligned only when you explicitly invoke the command @code{c-backslash-region} (@kbd{C-c C-\}). @end defopt +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Macros with ;, , Macro Backslashes, Custom Macros +@comment node-name, next, previous, up +@section Macros with semicolons +@cindex macros with semicolons +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Macros which needn't (or mustn't) be followed by a semicolon when you +invoke them, @dfn{macros with semicolons}, are very common. These can +cause @ccmode{} to parse the next line wrongly as a +@code{statement-cont} (@pxref{Function Symbols}) and thus mis-indent +it. + +You can prevent this by specifying which macros have semicolons. It +doesn't matter whether or not such a macro has a parameter list: + +@defopt c-macro-names-with-semicolon +@vindex macro-names-with-semicolon (c-) +This buffer-local variable specifies which macros have semicolons. +After setting its value, you need to call +@code{c-make-macro-with-semi-re} for it to take effect. It should be +set to one of these values: + +@table @asis +@item nil +There are no macros with semicolons. +@item a list of strings +Each string is the name of a macro with a semicolon. Only valid +@code{#define} names are allowed here. For example, to set the +default value, you could write the following into your @file{.emacs}: + +@example +(setq c-macro-names-with-semicolon + '("Q_OBJECT" "Q_PROPERTY" "Q_DECLARE" "Q_ENUMS")) +@end example + +@item a regular expression +This matches each symbol which is a macro with a semicolon. It must +not match any string which isn't a valid @code{#define} name. For +example: + +@example +(setq c-macro-names-with-semicolon + "\\<\\(CLEAN_UP_AND_RETURN\\|Q_[[:upper:]]+\\)\\>") +@end example +@end table +@end defopt + +@defun c-make-macro-with-semi-re +@findex make-macro-with-semi-re (c-) +Call this (non-interactive) function, which sets internal variables, +each time you change the value of +@code{c-macro-names-with-semicolon}. It takes no arguments, and its +return value has no meaning. This function is called by @ccmode{}'s +initialization code. +@end defun + @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @node Odds and Ends, Sample .emacs File, Custom Macros, Top @comment node-name, next, previous, up diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index e5b4d7e35a4..93da6e3e2be 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -744,19 +744,20 @@ be after it." ;; V i r t u a l S e m i c o l o n s ;; ;; In most CC Mode languages, statements are terminated explicitly by -;; semicolons or closing braces. In some of the CC modes (currently only AWK -;; Mode (April 2004)), statements are (or can be) terminated by EOLs. Such a -;; statement is said to be terminated by a "virtual semicolon" (VS). A -;; statement terminated by an actual semicolon or brace is never considered to -;; have a VS. +;; semicolons or closing braces. In some of the CC modes (currently AWK Mode +;; and certain user-specified #define macros in C, C++, etc. (November 2008)), +;; statements are (or can be) terminated by EOLs. Such a statement is said to +;; be terminated by a "virtual semicolon" (VS). A statement terminated by an +;; actual semicolon or brace is never considered to have a VS. ;; ;; The indentation engine (or whatever) tests for a VS at a specific position ;; by invoking the macro `c-at-vsemi-p', which in its turn calls the mode ;; specific function (if any) which is the value of the language variable -;; `c-at-vsemi-p-fn'. The actual details of what constitutes a VS in a -;; language are thus encapsulated in code specific to that language -;; (e.g. cc-awk.el). `c-at-vsemi-p' returns non-nil if point (or the optional -;; parameter POS) is at a VS, nil otherwise. +;; `c-at-vsemi-p-fn'. This function should only use "low-level" features of +;; CC Mode, i.e. features which won't trigger infinite recursion. ;-) The +;; actual details of what constitutes a VS in a language are thus encapsulated +;; in code specific to that language (e.g. cc-awk.el). `c-at-vsemi-p' returns +;; non-nil if point (or the optional parameter POS) is at a VS, nil otherwise. ;; ;; The language specific function might well do extensive analysis of the ;; source text, and may use a cacheing scheme to speed up repeated calls. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index b2c548847c3..c7e02a1bbd5 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -1149,42 +1149,65 @@ the line. If this virtual semicolon is _at_ from, the function recognizes it. Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." - (let ((skip-chars c-stmt-delim-chars) - lit-range) - (save-excursion - (catch 'done - (goto-char from) - (while (progn (skip-chars-forward skip-chars to) - (< (point) to)) - (cond - ((setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment? - (goto-char (cdr lit-range))) - ((eq (char-after) ?:) - (forward-char) - (if (and (eq (char-after) ?:) - (< (point) to)) - ;; Ignore scope operators. - (forward-char) - (setq c-maybe-labelp (1- (point))))) - ((eq (char-after) ??) - ;; A question mark. Can't be a label, so stop - ;; looking for more : and ?. - (setq c-maybe-labelp nil - skip-chars (substring c-stmt-delim-chars 0 -2))) - ((memq (char-after) '(?# ?\n ?\r)) ; A virtual semicolon? - (if (and (eq (char-before) ?\\) (memq (char-after) '(?\n ?\r))) - (backward-char)) - (skip-chars-backward " \t" from) - (if (c-at-vsemi-p) - (throw 'done (point)) - (forward-line))) - (t (throw 'done (point))))) - ;; In trailing space after an as yet undetected virtual semicolon? - (c-backward-syntactic-ws from) - (if (and (< (point) to) - (c-at-vsemi-p)) - (point) - nil))))) + (let* ((skip-chars + ;; If the current language has CPP macros, insert # into skip-chars. + (if c-opt-cpp-symbol + (concat (substring c-stmt-delim-chars 0 1) ; "^" + c-opt-cpp-symbol ; usually "#" + (substring c-stmt-delim-chars 1)) ; e.g. ";{}?:" + c-stmt-delim-chars)) + (non-skip-list + (append (substring skip-chars 1) nil)) ; e.g. (?# ?\; ?{ ?} ?? ?:) + lit-range vsemi-pos) + (save-restriction + (widen) + (save-excursion + (catch 'done + (goto-char from) + (while (progn (skip-chars-forward + skip-chars + (min to (c-point 'bonl))) + (< (point) to)) + (cond + ;; Virtual semicolon? + ((and (bolp) + (save-excursion + (progn + (if (setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment? + (goto-char (car lit-range))) + (c-backward-syntactic-ws) ; ? put a limit here, maybe? + (setq vsemi-pos (point)) + (c-at-vsemi-p)))) + (throw 'done vsemi-pos)) + ;; In a string/comment? + ((setq lit-range (c-literal-limits)) + (goto-char (cdr lit-range))) + ((eq (char-after) ?:) + (forward-char) + (if (and (eq (char-after) ?:) + (< (point) to)) + ;; Ignore scope operators. + (forward-char) + (setq c-maybe-labelp (1- (point))))) + ((eq (char-after) ??) + ;; A question mark. Can't be a label, so stop + ;; looking for more : and ?. + (setq c-maybe-labelp nil + skip-chars (substring c-stmt-delim-chars 0 -2))) + ;; At a CPP construct? + ((and c-opt-cpp-symbol (looking-at c-opt-cpp-symbol) + (save-excursion + (forward-line 0) + (looking-at c-opt-cpp-prefix))) + (c-end-of-macro)) + ((memq (char-after) non-skip-list) + (throw 'done (point))))) + ;; In trailing space after an as yet undetected virtual semicolon? + (c-backward-syntactic-ws from) + (if (and (< (point) to) + (c-at-vsemi-p)) + (point) + nil)))))) (defun c-at-statement-start-p () "Return non-nil if the point is at the first token in a statement @@ -7158,12 +7181,14 @@ comment at the start of cc-engine.el for more info." ;; Check that we're not after a token that can't precede a label. (or ;; Trivially succeeds when there's no preceding token. + ;; Succeeds when we're at a virtual semicolon. (if preceding-token-end (<= preceding-token-end (point-min)) (save-excursion (c-backward-syntactic-ws) (setq preceding-token-end (point)) - (bobp))) + (or (bobp) + (c-at-vsemi-p)))) ;; Check if we're after a label, if we're after a closing ;; paren that belong to statement, and with @@ -8372,6 +8397,57 @@ comment at the start of cc-engine.el for more info." paren-state) containing-sexp))))) +(defun c-at-macro-vsemi-p (&optional pos) + ;; Is there a "virtual semicolon" at POS or point? + ;; (See cc-defs.el for full details of "virtual semicolons".) + ;; + ;; This is true when point is at the last non syntactic WS position on the + ;; line, there is a macro call last on the line, and this particular macro's + ;; name is defined by the regexp `c-vs-macro-regexp' as not needing a + ;; semicolon. + (save-excursion + (save-restriction + (widen) + (if pos + (goto-char pos) + (setq pos (point))) + (and + c-macro-with-semi-re + (not (c-in-literal)) + (eq (skip-chars-backward " \t") 0) + + ;; Check we've got nothing after this except comments and empty lines + ;; joined by escaped EOLs. + (skip-chars-forward " \t") ; always returns non-nil. + (progn + (while ; go over 1 block comment per iteration. + (and + (looking-at "\\(\\\\[\n\r][ \t]*\\)*") + (goto-char (match-end 0)) + (cond + ((looking-at c-block-comment-start-regexp) + (and (forward-comment 1) + (skip-chars-forward " \t"))) ; always returns non-nil + ((looking-at c-line-comment-start-regexp) + (end-of-line) + nil) + (t nil)))) + (eolp)) + + (goto-char pos) + (progn (c-backward-syntactic-ws) + (eq (point) pos)) + + ;; Check for one of the listed macros being before point. + (or (not (eq (char-before) ?\))) + (when (c-go-list-backward) + (c-backward-syntactic-ws) + t)) + (c-simple-skip-symbol-backward) + (looking-at c-macro-with-semi-re))))) + +(defun c-macro-vsemi-status-unknown-p () t) ; See cc-defs.el. + ;; `c-guess-basic-syntax' and the functions that precedes it below ;; implements the main decision tree for determining the syntactic diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index fd817e3b4f4..9a83d5196db 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1277,9 +1277,11 @@ casts and declarations are fontified. Used on level 2 and higher." (when ;; The result of the form below is true when we don't recognize a ;; declaration or cast. - (if (and (eq (get-text-property (point) 'face) - 'font-lock-keyword-face) - (looking-at c-not-decl-init-keywords)) + (if (or (and (eq (get-text-property (point) 'face) + 'font-lock-keyword-face) + (looking-at c-not-decl-init-keywords)) + (and c-macro-with-semi-re + (looking-at c-macro-with-semi-re))) ; 2008-11-04 ;; Don't do anything more if we're looking at a keyword that ;; can't start a declaration. t diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 279c5e46c46..09f8b318378 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -508,6 +508,31 @@ parameters \(point-min), \(point-max) and ." (c-lang-defvar c-before-font-lock-function (c-lang-const c-before-font-lock-function)) + +;;; Syntactic analysis ("virtual semicolons") for line-oriented languages (AWK). +(c-lang-defconst c-at-vsemi-p-fn + "Contains a function \"Is there a virtual semicolon at POS or point?\". +Such a function takes one optional parameter, a buffer position (defaults to +point), and returns nil or t. This variable contains nil for languages which +don't have EOL terminated statements. " + t nil + (c c++ objc) 'c-at-macro-vsemi-p + awk 'c-awk-at-vsemi-p) +(c-lang-defvar c-at-vsemi-p-fn (c-lang-const c-at-vsemi-p-fn)) + +(c-lang-defconst c-vsemi-status-unknown-p-fn + "Contains a function \"are we unsure whether there is a virtual semicolon on this line?\". +The (admittedly kludgey) purpose of such a function is to prevent an infinite +recursion in c-beginning-of-statement-1 when point starts at a `while' token. +The function MUST NOT UNDER ANY CIRCUMSTANCES call c-beginning-of-statement-1, +even indirectly. This variable contains nil for languages which don't have +EOL terminated statements." + t nil + (c c++ objc) 'c-macro-vsemi-status-unknown-p + awk 'c-awk-vsemi-status-unknown-p) +(c-lang-defvar c-vsemi-status-unknown-p-fn + (c-lang-const c-vsemi-status-unknown-p-fn)) + ;;; Lexer-level syntax (identifiers, tokens etc). @@ -737,6 +762,12 @@ literal are multiline." (c-lang-defvar c-multiline-string-start-char (c-lang-const c-multiline-string-start-char)) +(c-lang-defconst c-opt-cpp-symbol + "The symbol which starts preprocessor constructs when in the margin." + t "#" + (java awk) nil) +(c-lang-defvar c-opt-cpp-symbol (c-lang-const c-opt-cpp-symbol)) + (c-lang-defconst c-opt-cpp-prefix "Regexp matching the prefix of a cpp directive in the languages that normally use that macro preprocessor. Tested at bol or at boi. @@ -785,6 +816,8 @@ file name in angle brackets or quotes." definition, or nil if the language doesn't have any." t (if (c-lang-const c-opt-cpp-prefix) "define")) +(c-lang-defvar c-opt-cpp-macro-define + (c-lang-const c-opt-cpp-macro-define)) (c-lang-defconst c-opt-cpp-macro-define-start ;; Regexp matching everything up to the macro body of a cpp define, or the @@ -1171,14 +1204,12 @@ operators." ;; optimize `c-crosses-statement-barrier-p' somewhat, it's assumed to ;; begin with "^" to negate the set. If ? : operators should be ;; detected then the string must end with "?:". - t "^;{}?:" - awk "^;{}#\n\r?:") ; The newline chars gets special treatment. + t "^;{}?:") (c-lang-defvar c-stmt-delim-chars (c-lang-const c-stmt-delim-chars)) (c-lang-defconst c-stmt-delim-chars-with-comma ;; Variant of `c-stmt-delim-chars' that additionally contains ','. - t "^;,{}?:" - awk "^;,{}\n\r?:") ; The newline chars gets special treatment. + t "^;,{}?:") (c-lang-defvar c-stmt-delim-chars-with-comma (c-lang-const c-stmt-delim-chars-with-comma)) @@ -1238,7 +1269,6 @@ properly." re))) (c-lang-defvar c-comment-start-regexp (c-lang-const c-comment-start-regexp)) -;;;; Added by ACM, 2003/9/18. (c-lang-defconst c-block-comment-start-regexp ;; Regexp which matches the start of a block comment (if such exists in the ;; language) @@ -1248,6 +1278,15 @@ properly." (c-lang-defvar c-block-comment-start-regexp (c-lang-const c-block-comment-start-regexp)) +(c-lang-defconst c-line-comment-start-regexp + ;; Regexp which matches the start of a line comment (if such exists in the + ;; language; it does in all 7 CC Mode languages). + t (if (c-lang-const c-line-comment-starter) + (regexp-quote (c-lang-const c-line-comment-starter)) + "\\<\\>")) +(c-lang-defvar c-line-comment-start-regexp + (c-lang-const c-line-comment-start-regexp)) + (c-lang-defconst c-literal-start-regexp ;; Regexp to match the start of comments and string literals. t (concat (c-lang-const c-comment-start-regexp) @@ -1474,29 +1513,6 @@ properly." "\\)")) (c-lang-defvar c-syntactic-eol (c-lang-const c-syntactic-eol)) - -;;; Syntactic analysis ("virtual semicolons") for line-oriented languages (AWK). -(c-lang-defconst c-at-vsemi-p-fn - "Contains a function \"Is there a virtual semicolon at POS or point?\". -Such a function takes one optional parameter, a buffer position (defaults to -point), and returns nil or t. This variable contains nil for languages which -don't have EOL terminated statements. " - t nil - awk 'c-awk-at-vsemi-p) -(c-lang-defvar c-at-vsemi-p-fn (c-lang-const c-at-vsemi-p-fn)) - -(c-lang-defconst c-vsemi-status-unknown-p-fn - "Contains a function \"are we unsure whether there is a virtual semicolon on this line?\". -The (admittedly kludgey) purpose of such a function is to prevent an infinite -recursion in c-beginning-of-statement-1 when point starts at a `while' token. -The function MUST NOT UNDER ANY CIRCUMSTANCES call c-beginning-of-statement-1, -even indirectly. This variable contains nil for languages which don't have -EOL terminated statements." - t nil - awk 'c-awk-vsemi-status-unknown-p) -(c-lang-defvar c-vsemi-status-unknown-p-fn - (c-lang-const c-vsemi-status-unknown-p-fn)) - ;;; Defun functions diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index eec63b4fa3b..a6bf241f0db 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1187,6 +1187,7 @@ Key bindings: abbrev-mode t) (use-local-map c-mode-map) (c-init-language-vars-for 'c-mode) + (c-make-macro-with-semi-re) ; matches macro names whose expansion ends with ; (c-common-init 'c-mode) (easy-menu-add c-c-menu) (cc-imenu-init cc-imenu-c-generic-expression) @@ -1246,6 +1247,7 @@ Key bindings: abbrev-mode t) (use-local-map c++-mode-map) (c-init-language-vars-for 'c++-mode) + (c-make-macro-with-semi-re) ; matches macro names whose expansion ends with ; (c-common-init 'c++-mode) (easy-menu-add c-c++-menu) (cc-imenu-init cc-imenu-c++-generic-expression) @@ -1303,6 +1305,7 @@ Key bindings: abbrev-mode t) (use-local-map objc-mode-map) (c-init-language-vars-for 'objc-mode) + (c-make-macro-with-semi-re) ; matches macro names whose expansion ends with ; (c-common-init 'objc-mode) (easy-menu-add c-objc-menu) (cc-imenu-init nil 'cc-imenu-objc-function) diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 58dc1737c5a..055d5f4c57c 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -1608,6 +1608,54 @@ names).")) ;; Non-customizable variables, still part of the interface to CC Mode +(defvar c-macro-with-semi-re nil + ;; Regular expression which matches a (#define'd) symbol whose expansion + ;; ends with a semicolon. + ;; + ;; This variable should be set by `c-make-macros-with-semi-re' rather than + ;; directly. +) +(make-variable-buffer-local 'c-macro-with-semi-re) + +(defun c-make-macro-with-semi-re () + ;; Convert `c-macro-names-with-semicolon' into the regexp + ;; `c-macro-with-semi-re' (or just copy it if it's already a re). + (setq c-macro-with-semi-re + (and + c-opt-cpp-macro-define + (cond + ((stringp c-macro-names-with-semicolon) + (copy-sequence c-macro-names-with-semicolon)) + ((consp c-macro-names-with-semicolon) + (concat + "\\<" + (regexp-opt c-macro-names-with-semicolon) + "\\>")) ; N.B. the PAREN param of regexp-opt isn't supported by + ; all XEmacsen. + ((null c-macro-names-with-semicolon) + nil) + (t (error "c-make-macro-with-semi-re: invalid \ +c-macro-names-with-semicolon: %s" + c-macro-names-with-semicolon)))))) + +(defvar c-macro-names-with-semicolon + '("Q_OBJECT" "Q_PROPERTY" "Q_DECLARE" "Q_ENUMS") + "List of #defined symbols whose expansion ends with a semicolon. +Alternatively it can be a string, a regular expression which +matches all such symbols. + +The \"symbols\" must be syntactically valid identifiers in the +target language \(C, C++, Objective C), or \(as the case may be) +the regular expression must match only valid identifiers. + +If you change this variable's value, call the function +`c-make-macros-with-semi-re' to set the necessary internal +variables. + +Note that currently \(2008-11-04) this variable is a prototype, +and is likely to disappear or change its form soon.") +(make-variable-buffer-local 'c-macro-names-with-semicolon) + (defvar c-file-style nil "Variable interface for setting style via File Local Variables. In a file's Local Variable section, you can set this variable to a -- 2.39.5