Merge from emacs-23
[bpt/emacs.git] / lisp / progmodes / cc-engine.el
index c45913e..1ee3c29 100644 (file)
@@ -1,13 +1,14 @@
 ;;; cc-engine.el --- core syntax guessing engine for CC mode
 
 ;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
 ;;   Free Software Foundation, Inc.
 
 ;; Authors:    2001- Alan Mackenzie
 ;;             1998- Martin Stjernholm
 ;;             1992-1999 Barry A. Warsaw
-;;             1987 Dave Detlefs and Stewart Clamen
+;;             1987 Dave Detlefs
+;;             1987 Stewart Clamen
 ;;             1985 Richard M. Stallman
 ;; Maintainer: bug-cc-mode@gnu.org
 ;; Created:    22-Apr-1997 (split from cc-mode.el)
 ;; Note: This doc is for internal use only.  Other packages should not
 ;; assume that these text properties are used as described here.
 ;;
+;; 'category
+;;   Used for "indirection".  With its help, some other property can
+;;   be cheaply and easily switched on or off everywhere it occurs.
+;;
 ;; 'syntax-table
 ;;   Used to modify the syntax of some characters.  It is used to
 ;;   mark the "<" and ">" of angle bracket parens with paren syntax, and
@@ -255,6 +260,27 @@ comment at the start of cc-engine.el for more info."
             (forward-char)
             t))))
 
+(defun c-syntactic-end-of-macro ()
+  ;; Go to the end of a CPP directive, or a "safe" pos just before.
+  ;;
+  ;; This is normally the end of the next non-escaped line.  A "safe"
+  ;; position is one not within a string or comment.  (The EOL on a line
+  ;; comment is NOT "safe").
+  ;;
+  ;; This function must only be called from the beginning of a CPP construct.
+  ;;
+  ;; Note that this function might do hidden buffer changes.  See the comment
+  ;; at the start of cc-engine.el for more info.
+  (let* ((here (point))
+        (there (progn (c-end-of-macro) (point)))
+        (s (parse-partial-sexp here there)))
+    (while (and (or (nth 3 s)   ; in a string
+                   (nth 4 s))   ; in a comment (maybe at end of line comment)
+               (> there here))  ; No infinite loops, please.
+      (setq there (1- (nth 8 s)))
+      (setq s (parse-partial-sexp here there)))
+    (point)))
+
 (defun c-forward-over-cpp-define-id ()
   ;; Assuming point is at the "#" that introduces a preprocessor
   ;; directive, it's moved forward to the end of the identifier which is
@@ -421,7 +447,7 @@ comment at the start of cc-engine.el for more info."
   (c-put-char-property pos 'c-type value))
 
 (defun c-clear-c-type-property (from to value)
-  ;; Remove all occurences of the c-type property that has the given
+  ;; Remove all occurrences of the c-type property that has the given
   ;; value in the region between FROM and TO.  VALUE is assumed to not
   ;; be nil.
   ;;
@@ -529,7 +555,7 @@ the previous one if already at the beginning of one.  Only
 statements/declarations on the same level are considered, i.e. don't
 move into or out of sexps (not even normal expression parentheses).
 
-If point is already at the earliest statment within braces or parens,
+If point is already at the earliest statement within braces or parens,
 this function doesn't move back into any whitespace preceding it; it
 returns 'same in this case.
 
@@ -553,7 +579,7 @@ start of the definition in a \"#define\".  Also stop at start of
 macros before leaving them.
 
 Return:
-'label          if stopped at a label;
+'label          if stopped at a label or \"case...:\" or \"default:\";
 'same           if stopped at the beginning of the current statement;
 'up             if stepped to a containing statement;
 'previous       if stepped to a preceding statement;
@@ -579,7 +605,7 @@ comment at the start of cc-engine.el for more info."
   ;; The bulk of this function is a pushdown automaton that looks at statement
   ;; boundaries and the tokens (such as "while") in c-opt-block-stmt-key.  Its
   ;; purpose is to keep track of nested statements, ensuring that such
-  ;; statments are skipped over in their entirety (somewhat akin to what C-M-p
+  ;; statements are skipped over in their entirety (somewhat akin to what C-M-p
   ;; does with nested braces/brackets/parentheses).
   ;;
   ;; Note: The position of a boundary is the following token.
@@ -664,7 +690,7 @@ comment at the start of cc-engine.el for more info."
        (c-stmt-delim-chars (if comma-delim
                                c-stmt-delim-chars-with-comma
                              c-stmt-delim-chars))
-       c-in-literal-cache c-maybe-labelp saved
+       c-in-literal-cache c-maybe-labelp after-case:-pos saved
        ;; Current position.
        pos
        ;; Position of last stmt boundary character (e.g. ;).
@@ -978,7 +1004,7 @@ comment at the start of cc-engine.el for more info."
                            ;; Like a C "continue".  Analyze the next sexp.
                            (throw 'loop t)))
 
-                       sexp-loop-continue-pos) ; End of "go back a sexp" loop.
+                       sexp-loop-continue-pos) ; End of "go back a sexp" loop condition.
                    (goto-char sexp-loop-continue-pos)
                    (setq sexp-loop-end-pos sexp-loop-continue-pos
                          sexp-loop-continue-pos nil))))
@@ -996,19 +1022,16 @@ comment at the start of cc-engine.el for more info."
                  ;; `c-crosses-statement-barrier-p' has found a colon, so we
                  ;; might be in a label now.  Have we got a real label
                  ;; (including a case label) or something like C++'s "public:"?
-                 (if (or (not (looking-at c-nonlabel-token-key)) ; proper label
-                         (save-excursion ; e.g. "case 'a':" ?
-                           (and (c-safe (c-backward-sexp) t)
-                                (looking-at "\\<case\\>")))) ; FIXME!!! this is
-                                       ; wrong for AWK.  2006/1/14.
-                     (progn
-                       (if after-labels-pos ; Have we already encountered a label?
-                           (if (not last-label-pos)
-                               (setq last-label-pos (or tok start)))
-                         (setq after-labels-pos (or tok start)))
-                       (setq c-maybe-labelp t
-                             label-good-pos nil))
-                   (setq c-maybe-labelp nil))) ; bogus "label"
+                 ;; A case label might use an expression rather than a token.
+                 (setq after-case:-pos (or tok start))
+                 (if (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
+                     (setq c-maybe-labelp nil)
+                   (if after-labels-pos ; Have we already encountered a label?
+                       (if (not last-label-pos)
+                           (setq last-label-pos (or tok start)))
+                     (setq after-labels-pos (or tok start)))
+                   (setq c-maybe-labelp t
+                         label-good-pos nil))) ; bogus "label"
 
                (when (and (not label-good-pos) ; i.e. no invalid "label"'s yet
                                                ; been found.
@@ -1063,8 +1086,17 @@ comment at the start of cc-engine.el for more info."
                ;; Might have jumped over several labels.  Go to the last one.
                (setq pos last-label-pos)))))
 
-      ;; Skip over the unary operators that can start the statement.
+      ;; Have we got "case <expression>:"?
       (goto-char pos)
+      (when (and after-case:-pos
+                (not (eq ret 'beginning))
+                (looking-at c-case-kwds-regexp))
+       (if (< after-case:-pos start)
+           (setq pos after-case:-pos))
+       (if (eq ret 'same)
+           (setq ret 'label)))
+
+      ;; Skip over the unary operators that can start the statement.
       (while (progn
               (c-backward-syntactic-ws)
               ;; protect AWK post-inc/decrement operators, etc.
@@ -1940,10 +1972,18 @@ comment at the start of cc-engine.el for more info."
 \f
 ;; A system for finding noteworthy parens before the point.
 
+(defconst c-state-cache-too-far 5000)
+;; A maximum comfortable scanning distance, e.g. between
+;; `c-state-cache-good-pos' and "HERE" (where we call c-parse-state).  When
+;; this distance is exceeded, we take "emergency meausures", e.g. by clearing
+;; the cache and starting again from point-min or a beginning of defun.  This
+;; value can be tuned for efficiency or set to a lower value for testing.
+
 (defvar c-state-cache nil)
 (make-variable-buffer-local 'c-state-cache)
 ;; The state cache used by `c-parse-state' to cut down the amount of
-;; searching.  It's the result from some earlier `c-parse-state' call.
+;; searching.  It's the result from some earlier `c-parse-state' call.  See
+;; `c-parse-state''s doc string for details of its structure.
 ;;
 ;; The use of the cached info is more effective if the next
 ;; `c-parse-state' call is on a line close by the one the cached state
@@ -1952,18 +1992,12 @@ comment at the start of cc-engine.el for more info."
 ;; most effective if `c-parse-state' is used on each line while moving
 ;; forward.
 
-(defvar c-state-cache-start 1)
-(make-variable-buffer-local 'c-state-cache-start)
-;; This is (point-min) when `c-state-cache' was calculated, since a
-;; change of narrowing is likely to affect the parens that are visible
-;; before the point.
-
 (defvar c-state-cache-good-pos 1)
 (make-variable-buffer-local 'c-state-cache-good-pos)
-;; This is a position where `c-state-cache' is known to be correct.
-;; It's a position inside one of the recorded unclosed parens or the
-;; top level, but not further nested inside any literal or subparen
-;; that is closed before the last recorded position.
+;; This is a position where `c-state-cache' is known to be correct, or
+;; nil (see below).  It's a position inside one of the recorded unclosed
+;; parens or the top level, but not further nested inside any literal or
+;; subparen that is closed before the last recorded position.
 ;;
 ;; The exact position is chosen to try to be close to yet earlier than
 ;; the position where `c-state-cache' will be called next.  Right now
@@ -1971,313 +2005,1074 @@ comment at the start of cc-engine.el for more info."
 ;; closing paren (of any type) before the line on which
 ;; `c-parse-state' was called.  That is chosen primarily to work well
 ;; with refontification of the current line.
+;;
+;; 2009-07-28: When `c-state-point-min' and the last position where
+;; `c-parse-state' or for which `c-invalidate-state-cache' was called, are
+;; both in the same literal, there is no such "good position", and
+;; c-state-cache-good-pos is then nil.  This is the ONLY circumstance in which
+;; it can be nil.  In this case, `c-state-point-min-literal' will be non-nil.
+;;
+;; 2009-06-12: In a brace desert, c-state-cache-good-pos may also be in
+;; the middle of the desert, as long as it is not within a brace pair
+;; recorded in `c-state-cache' or a paren/bracket pair.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; We maintain a simple cache of positions which aren't in a literal, so as to
+;; speed up testing for non-literality.
+(defconst c-state-nonlit-pos-interval 10000)
+;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
+
+(defvar c-state-nonlit-pos-cache nil)
+(make-variable-buffer-local 'c-state-nonlit-pos-cache)
+;; A list of buffer positions which are known not to be in a literal.  This is
+;; ordered with higher positions at the front of the list.  Only those which
+;; are less than `c-state-nonlit-pos-cache-limit' are valid.
+
+(defvar c-state-nonlit-pos-cache-limit 1)
+(make-variable-buffer-local 'c-state-nonlit-pos-cache-limit)
+;; An upper limit on valid entries in `c-state-nonlit-pos-cache'.  This is
+;; reduced by buffer changes, and increased by invocations of
+;; `c-state-literal-at'.
+
+(defsubst c-state-pp-to-literal (from to)
+  ;; Do a parse-partial-sexp from FROM to TO, returning the bounds of any
+  ;; literal at TO as a cons, otherwise NIL.
+  ;; FROM must not be in a literal, and the buffer should already be wide
+  ;; enough.
+  (save-excursion
+    (let ((s (parse-partial-sexp from to)))
+      (when (or (nth 3 s) (nth 4 s))   ; in a string or comment
+       (parse-partial-sexp (point) (point-max)
+                           nil                  ; TARGETDEPTH
+                           nil                  ; STOPBEFORE
+                           s                    ; OLDSTATE
+                           'syntax-table)       ; stop at end of literal
+       (cons (nth 8 s) (point))))))
+
+(defun c-state-literal-at (here)
+  ;; If position HERE is inside a literal, return (START . END), the
+  ;; boundaries of the literal (which may be outside the accessible bit of the
+  ;; buffer).  Otherwise, return nil.
+  ;;
+  ;; This function is almost the same as `c-literal-limits'.  It differs in
+  ;; that it is a lower level function, and that it rigourously follows the
+  ;; syntax from BOB, whereas `c-literal-limits' uses a "local" safe position.
+  (save-restriction
+    (widen)
+    (save-excursion
+      (let ((c c-state-nonlit-pos-cache)
+           pos npos lit)
+       ;; Trim the cache to take account of buffer changes.
+       (while (and c (> (car c) c-state-nonlit-pos-cache-limit))
+         (setq c (cdr c)))
+       (setq c-state-nonlit-pos-cache c)
+
+       (while (and c (> (car c) here))
+         (setq c (cdr c)))
+       (setq pos (or (car c) (point-min)))
+
+       (while (<= (setq npos (+ pos c-state-nonlit-pos-interval))
+                  here)
+         (setq lit (c-state-pp-to-literal pos npos))
+         (setq pos (or (cdr lit) npos)) ; end of literal containing npos.
+         (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
+
+       (if (> pos c-state-nonlit-pos-cache-limit)
+           (setq c-state-nonlit-pos-cache-limit pos))
+       (if (< pos here)
+           (setq lit (c-state-pp-to-literal pos here)))
+       lit))))
+
+(defsubst c-state-lit-beg (pos)
+  ;; Return the start of the literal containing POS, or POS itself.
+  (or (car (c-state-literal-at pos))
+      pos))
+
+(defsubst c-state-cache-non-literal-place (pos state)
+  ;; Return a position outside of a string/comment at or before POS.
+  ;; STATE is the parse-partial-sexp state at POS.
+  (if (or (nth 3 state)                        ; in a string?
+         (nth 4 state))                ; in a comment?
+      (nth 8 state)
+    pos))
 
-(defsubst c-invalidate-state-cache (pos)
-  ;; Invalidate all info on `c-state-cache' that applies to the buffer
-  ;; at POS or higher.  This is much like `c-whack-state-after', but
-  ;; it never changes a paren pair element into an open paren element.
-  ;; Doing that would mean that the new open paren wouldn't have the
-  ;; required preceding paren pair element.
-  (while (and (or c-state-cache
-                 (when (< pos c-state-cache-good-pos)
-                   (setq c-state-cache-good-pos 1)
-                   nil))
-             (let ((elem (car c-state-cache)))
-               (if (consp elem)
-                   (or (< pos (cdr elem))
-                       (when (< pos c-state-cache-good-pos)
-                         (setq c-state-cache-good-pos (cdr elem))
-                         nil))
-                 (or (<= pos elem)
-                     (when (< pos c-state-cache-good-pos)
-                       (setq c-state-cache-good-pos (1+ elem))
-                       nil)))))
-    (setq c-state-cache (cdr c-state-cache))))
-
-(defun c-get-fallback-start-pos (here)
-  ;; Return the start position for building `c-state-cache' from
-  ;; scratch.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Stuff to do with point-min, and coping with any literal there.
+(defvar c-state-point-min 1)
+(make-variable-buffer-local 'c-state-point-min)
+;; This is (point-min) when `c-state-cache' was last calculated.  A change of
+;; narrowing is likely to affect the parens that are visible before the point.
+
+(defvar c-state-point-min-lit-type nil)
+(make-variable-buffer-local 'c-state-point-min-lit-type)
+(defvar c-state-point-min-lit-start nil)
+(make-variable-buffer-local 'c-state-point-min-lit-start)
+;; These two variables define the literal, if any, containing point-min.
+;; Their values are, respectively, 'string, c, or c++, and the start of the
+;; literal.  If there's no literal there, they're both nil.
+
+(defvar c-state-min-scan-pos 1)
+(make-variable-buffer-local 'c-state-min-scan-pos)
+;; This is the earliest buffer-pos from which scanning can be done.  It is
+;; either the end of the literal containing point-min, or point-min itself.
+;; It becomes nil if the buffer is changed earlier than this point.
+(defun c-state-get-min-scan-pos ()
+  ;; Return the lowest valid scanning pos.  This will be the end of the
+  ;; literal enclosing point-min, or point-min itself.
+  (or c-state-min-scan-pos
+      (save-restriction
+       (save-excursion
+         (widen)
+         (goto-char c-state-point-min-lit-start)
+         (if (eq c-state-point-min-lit-type 'string)
+             (forward-sexp)
+           (forward-comment 1))
+         (setq c-state-min-scan-pos (point))))))
+
+(defun c-state-mark-point-min-literal ()
+  ;; Determine the properties of any literal containing POINT-MIN, setting the
+  ;; variables `c-state-point-min-lit-type', `c-state-point-min-lit-start',
+  ;; and `c-state-min-scan-pos' accordingly.  The return value is meaningless.
+  (let ((p-min (point-min))
+       lit)
+    (save-restriction
+      (widen)
+      (setq lit (c-state-literal-at p-min))
+      (if lit
+         (setq c-state-point-min-lit-type
+               (save-excursion
+                 (goto-char (car lit))
+                 (cond
+                  ((looking-at c-block-comment-start-regexp) 'c)
+                  ((looking-at c-line-comment-starter) 'c++)
+                  (t 'string)))
+               c-state-point-min-lit-start (car lit)
+               c-state-min-scan-pos (cdr lit))
+       (setq c-state-point-min-lit-type nil
+             c-state-point-min-lit-start nil
+             c-state-min-scan-pos p-min)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; A variable which signals a brace dessert - helpful for reducing the number
+;; of fruitless backward scans.
+(defvar c-state-brace-pair-desert nil)
+(make-variable-buffer-local 'c-state-brace-pair-desert)
+;; Used only in `c-append-lower-brace-pair-to-state-cache'.  It is set when an
+;; that defun has searched backwards for a brace pair and not found one.  Its
+;; value is either nil or a cons (PA . FROM), where PA is the position of the
+;; enclosing opening paren/brace/bracket which bounds the backwards search (or
+;; nil when at top level) and FROM is where the backward search started.  It
+;; is reset to nil in `c-invalidate-state-cache'.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lowish level functions/macros which work directly on `c-state-cache', or a
+;; list of like structure.
+(defmacro c-state-cache-top-lparen (&optional cache)
+  ;; Return the address of the top left brace/bracket/paren recorded in CACHE
+  ;; (default `c-state-cache') (or nil).
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (caar ,cash)
+       (car ,cash))))
+
+(defmacro c-state-cache-top-paren (&optional cache)
+  ;; Return the address of the latest brace/bracket/paren (whether left or
+  ;; right) recorded in CACHE (default `c-state-cache') or nil.
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (cdar ,cash)
+       (car ,cash))))
+
+(defmacro c-state-cache-after-top-paren (&optional cache)
+  ;; Return the position just after the latest brace/bracket/paren (whether
+  ;; left or right) recorded in CACHE (default `c-state-cache') or nil.
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (cdar ,cash)
+       (and (car ,cash)
+           (1+ (car ,cash))))))
+
+(defun c-get-cache-scan-pos (here)
+  ;; From the state-cache, determine the buffer position from which we might
+  ;; scan forward to HERE to update this cache.  This position will be just
+  ;; after a paren/brace/bracket recorded in the cache, if possible, otherwise
+  ;; return the earliest position in the accessible region which isn't within
+  ;; a literal.  If the visible portion of the buffer is entirely within a
+  ;; literal, return NIL.
+  (let ((c c-state-cache) elt)
+    ;(while (>= (or (c-state-cache-top-lparen c) 1) here)
+    (while (and c
+               (>= (c-state-cache-top-lparen c) here))
+      (setq c (cdr c)))
+
+    (setq elt (car c))
+    (cond
+     ((consp elt)
+      (if (> (cdr elt) here)
+         (1+ (car elt))
+       (cdr elt)))
+     (elt (1+ elt))
+     ((<= (c-state-get-min-scan-pos) here)
+      (c-state-get-min-scan-pos))
+     (t nil))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Variables which keep track of preprocessor constructs.
+(defvar c-state-old-cpp-beg nil)
+(make-variable-buffer-local 'c-state-old-cpp-beg)
+(defvar c-state-old-cpp-end nil)
+(make-variable-buffer-local 'c-state-old-cpp-end)
+;; These are the limits of the macro containing point at the previous call of
+;; `c-parse-state', or nil.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Defuns which analyse the buffer, yet don't change `c-state-cache'.
+(defun c-get-fallback-scan-pos (here)
+  ;; Return a start position for building `c-state-cache' from
+  ;; scratch.  This will be at the top level, 2 defuns back.
   (save-excursion
     ;; Go back 2 bods, but ignore any bogus positions returned by
     ;; beginning-of-defun (i.e. open paren in column zero).
     (goto-char here)
     (let ((cnt 2))
       (while (not (or (bobp) (zerop cnt)))
-       (c-beginning-of-defun-1)
+       (c-beginning-of-defun-1)        ; Pure elisp BOD.
        (if (eq (char-after) ?\{)
            (setq cnt (1- cnt)))))
     (point)))
 
-(defun c-parse-state ()
-  ;; Find and record all noteworthy parens between some good point
-  ;; earlier in the file and point.  That good point is at least the
-  ;; beginning of the top-level construct we are in, or the beginning
-  ;; of the preceding top-level construct if we aren't in one.
-  ;;
-  ;; The returned value is a list of the noteworthy parens with the
-  ;; last one first.  If an element in the list is an integer, it's
-  ;; the position of an open paren which has not been closed before
-  ;; the point.  If an element is a cons, it gives the position of a
-  ;; closed brace paren pair; the car is the start paren position and
-  ;; the cdr is the position following the closing paren.  Only the
-  ;; last closed brace paren pair before each open paren and before
-  ;; the point is recorded, and thus the state never contains two cons
-  ;; elements in succession.
+(defun c-state-balance-parens-backwards (here- here+ top)
+  ;; Return the position of the opening paren/brace/bracket before HERE- which
+  ;; matches the outermost close p/b/b between HERE+ and TOP.  Except when
+  ;; there's a macro, HERE- and HERE+ are the same.  Like this:
+  ;;
+  ;;     ............................................
+  ;;     |                                          |
+  ;;     (    [ ( .........#macro.. )      ( )  ]  )
+  ;;     ^                 ^     ^                         ^
+  ;;     |                 |     |                         |
+  ;;   return            HERE- HERE+                      TOP
+  ;;
+  ;; If there aren't enough opening paren/brace/brackets, return the position
+  ;; of the outermost one found, or HERE- if there are none.  If there are no
+  ;; closeing p/b/bs between HERE+ and TOP, return HERE-.  HERE-/+ and TOP
+  ;; must not be inside literals.  Only the accessible portion of the buffer
+  ;; will be scanned.
+
+  ;; PART 1: scan from `here+' up to `top', accumulating ")"s which enclose
+  ;; `here'.  Go round the next loop each time we pass over such a ")".         These
+  ;; probably match "("s before `here-'.
+  (let (pos pa ren+1 lonely-rens)
+    (save-excursion
+      (save-restriction
+       (narrow-to-region (point-min) top) ; This can move point, sometimes.
+       (setq pos here+)
+       (c-safe
+         (while
+             (setq ren+1 (scan-lists pos 1 1)) ; might signal
+           (setq lonely-rens (cons ren+1 lonely-rens)
+                 pos ren+1)))))
+
+      ;; PART 2: Scan back before `here-' searching for the "("s
+      ;; matching/mismatching the ")"s found above. We only need to direct the
+      ;; caller to scan when we've encountered unmatched right parens.
+    (setq pos here-)
+    (when lonely-rens
+      (c-safe
+       (while
+           (and lonely-rens            ; actual values aren't used.
+                (setq pa (scan-lists pos -1 1)))
+         (setq pos pa)
+         (setq lonely-rens (cdr lonely-rens)))))
+    pos))
+
+(defun c-parse-state-get-strategy (here good-pos)
+  ;; Determine the scanning strategy for adjusting `c-parse-state', attempting
+  ;; to minimise the amount of scanning.  HERE is the pertinent position in
+  ;; the buffer, GOOD-POS is a position where `c-state-cache' (possibly with
+  ;; its head trimmed) is known to be good, or nil if there is no such
+  ;; position.
+  ;;
+  ;; The return value is a list, one of the following:
+  ;;
+  ;; o - ('forward CACHE-POS START-POINT) - scan forward from START-POINT,
+  ;;                                        which is not less than CACHE-POS.
+  ;; o - ('backward CACHE-POS nil) - scan backwards (from HERE).
+  ;; o - ('BOD nil START-POINT) - scan forwards from START-POINT, which is at the
+  ;;   top level.
+  ;; o - ('IN-LIT nil nil) - point is inside the literal containing point-min.
+  ;; , where CACHE-POS is the highest position recorded in `c-state-cache' at
+  ;; or below HERE.
+  (let ((cache-pos (c-get-cache-scan-pos here))        ; highest position below HERE in cache (or 1)
+       BOD-pos             ; position of 2nd BOD before HERE.
+       strategy            ; 'forward, 'backward, 'BOD, or 'IN-LIT.
+       start-point
+       how-far)                        ; putative scanning distance.
+    (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
+    (cond
+     ((< here (c-state-get-min-scan-pos))
+      (setq strategy 'IN-LIT
+           start-point nil
+           cache-pos nil
+           how-far 0))
+     ((<= good-pos here)
+      (setq strategy 'forward
+           start-point (max good-pos cache-pos)
+           how-far (- here start-point)))
+     ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
+      (setq strategy 'backward
+           how-far (- good-pos here)))
+     (t
+      (setq strategy 'forward
+             how-far (- here cache-pos)
+             start-point cache-pos)))
+
+    ;; Might we be better off starting from the top level, two defuns back,
+    ;; instead?
+    (when (> how-far c-state-cache-too-far)
+      (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
+      (if (< (- here BOD-pos) how-far)
+         (setq strategy 'BOD
+               start-point BOD-pos)))
+
+    (list
+     strategy
+     (and (memq strategy '(forward backward)) cache-pos)
+     (and (memq strategy '(forward BOD)) start-point))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Routines which change `c-state-cache' and associated values.
+(defun c-renarrow-state-cache ()
+  ;; The region (more precisely, point-min) has changed since we
+  ;; calculated `c-state-cache'.  Amend `c-state-cache' accordingly.
+  (if (< (point-min) c-state-point-min)
+      ;; If point-min has MOVED BACKWARDS then we drop the state completely.
+      ;; It would be possible to do a better job here and recalculate the top
+      ;; only.
+      (progn
+       (c-state-mark-point-min-literal)
+       (setq c-state-cache nil
+             c-state-cache-good-pos c-state-min-scan-pos
+             c-state-brace-pair-desert nil))
+
+    ;; point-min has MOVED FORWARD.
+
+    ;; Is the new point-min inside a (different) literal?
+    (unless (and c-state-point-min-lit-start ; at prev. point-min
+                (< (point-min) (c-state-get-min-scan-pos)))
+      (c-state-mark-point-min-literal))
+
+    ;; Cut off a bit of the tail from `c-state-cache'.
+    (let ((ptr (cons nil c-state-cache))
+         pa)
+      (while (and (setq pa (c-state-cache-top-lparen (cdr ptr)))
+                 (>= pa (point-min)))
+       (setq ptr (cdr ptr)))
+
+      (when (consp ptr)
+       (if (eq (cdr ptr) c-state-cache)
+           (setq c-state-cache nil
+                 c-state-cache-good-pos c-state-min-scan-pos)
+         (setcdr ptr nil)
+         (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen))))
+       )))
+
+  (setq c-state-point-min (point-min)))
+
+(defun c-append-lower-brace-pair-to-state-cache (from &optional upper-lim)
+  ;; If there is a brace pair preceding FROM in the buffer (not necessarily
+  ;; immediately preceding), push a cons onto `c-state-cache' to represent it.
+  ;; FROM must not be inside a literal.  If UPPER-LIM is non-nil, we append
+  ;; the highest brace pair whose "}" is below UPPER-LIM.
+  ;;
+  ;; Return non-nil when this has been done.
+  ;;
+  ;; This routine should be fast.  Since it can get called a LOT, we maintain
+  ;; `c-state-brace-pair-desert', a small cache of "failures", such that we
+  ;; reduce the time wasted in repeated fruitless searches in brace deserts.
+  (save-excursion
+    (save-restriction
+      (let ((bra from) ce              ; Positions of "{" and "}".
+           new-cons
+           (cache-pos (c-state-cache-top-lparen)) ; might be nil.
+           (macro-start-or-from
+            (progn (goto-char from)
+                   (c-beginning-of-macro)
+                   (point))))
+       (or upper-lim (setq upper-lim from))
+
+       ;; If we're essentially repeating a fruitless search, just give up.
+       (unless (and c-state-brace-pair-desert
+                    (eq cache-pos (car c-state-brace-pair-desert))
+                    (<= from (cdr c-state-brace-pair-desert)))
+         ;; Only search what we absolutely need to:
+         (if (and c-state-brace-pair-desert
+                  (> from (cdr c-state-brace-pair-desert)))
+             (narrow-to-region (cdr c-state-brace-pair-desert) (point-max)))
+
+         ;; In the next pair of nested loops, the inner one moves back past a
+         ;; pair of (mis-)matching parens or brackets; the outer one moves
+         ;; back over a sequence of unmatched close brace/paren/bracket each
+         ;; time round.
+         (while
+             (progn
+               (c-safe
+                 (while
+                     (and (setq ce (scan-lists bra -1 -1)) ; back past )/]/}; might signal
+                          (setq bra (scan-lists ce -1 1)) ; back past (/[/{; might signal
+                          (or (> ce upper-lim)
+                              (not (eq (char-after bra) ?\{))
+                              (and (goto-char bra)
+                                   (c-beginning-of-macro)
+                                   (< (point) macro-start-or-from))))))
+               (and ce (< ce bra)))
+           (setq bra ce))      ; If we just backed over an unbalanced closing
+                                       ; brace, ignore it.
+
+         (if (and ce (< bra ce) (eq (char-after bra) ?\{))
+             ;; We've found the desired brace-pair.
+             (progn
+               (setq new-cons (cons bra (1+ ce)))
+               (cond
+                ((consp (car c-state-cache))
+                 (setcar c-state-cache new-cons))
+                ((and (numberp (car c-state-cache)) ; probably never happens
+                      (< ce (car c-state-cache)))
+                 (setcdr c-state-cache
+                         (cons new-cons (cdr c-state-cache))))
+                (t (setq c-state-cache (cons new-cons c-state-cache)))))
+
+           ;; We haven't found a brace pair.  Record this.
+           (setq c-state-brace-pair-desert (cons cache-pos from))))))))
+
+(defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
+  ;; If BRA+1 is nil, do nothing.  Otherwise, BRA+1 is the buffer position
+  ;; following a {, and that brace has a (mis-)matching } (or ]), and we
+  ;; "push" "a" brace pair onto `c-state-cache'.
+  ;;
+  ;; Here "push" means overwrite the top element if it's itself a brace-pair,
+  ;; otherwise push it normally.
+  ;;
+  ;; The brace pair we push is normally the one surrounding BRA+1, but if the
+  ;; latter is inside a macro, not being a macro containing
+  ;; MACRO-START-OR-HERE, we scan backwards through the buffer for a non-macro
+  ;; base pair.  This latter case is assumed to be rare.
+  ;;
+  ;; Note: POINT is not preserved in this routine.
+  (if bra+1
+      (if (or (> bra+1 macro-start-or-here)
+             (progn (goto-char bra+1)
+                    (not (c-beginning-of-macro))))
+         (setq c-state-cache
+               (cons (cons (1- bra+1)
+                           (scan-lists bra+1 1 1))
+                     (if (consp (car c-state-cache))
+                         (cdr c-state-cache)
+                       c-state-cache)))
+       ;; N.B.  This defsubst codes one method for the simple, normal case,
+       ;; and a more sophisticated, slower way for the general case.  Don't
+       ;; eliminate this defsubst - it's a speed optimisation.
+       (c-append-lower-brace-pair-to-state-cache (1- bra+1)))))
+
+(defun c-append-to-state-cache (from)
+  ;; Scan the buffer from FROM to (point-max), adding elements into
+  ;; `c-state-cache' for braces etc.  Return a candidate for
+  ;; `c-state-cache-good-pos'.
+  ;;
+  ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
+  ;; any.  Typically, it is immediately after it.  It must not be inside a
+  ;; literal.
+  (let ((here-bol (c-point 'bol (point-max)))
+       (macro-start-or-here
+        (save-excursion (goto-char (point-max))
+                        (if (c-beginning-of-macro)
+                            (point)
+                          (point-max))))
+       pa+1                  ; pos just after an opening PAren (or brace).
+       (ren+1 from)          ; usually a pos just after an closing paREN etc.
+                             ; Is actually the pos. to scan for a (/{/[ from,
+                             ; which sometimes is after a silly )/}/].
+       paren+1               ; Pos after some opening or closing paren.
+       paren+1s              ; A list of `paren+1's; used to determine a
+                             ; good-pos.
+       bra+1 ce+1            ; just after L/R bra-ces.
+       bra+1s                ; list of OLD values of bra+1.
+       mstart)               ; start of a macro.
+
+    (save-excursion
+      ;; Each time round the following loop, we enter a succesively deeper
+      ;; level of brace/paren nesting.  (Except sometimes we "continue at
+      ;; the existing level".)  `pa+1' is a pos inside an opening
+      ;; brace/paren/bracket, usually just after it.
+      (while
+         (progn
+           ;; Each time round the next loop moves forward over an opening then
+           ;; a closing brace/bracket/paren.  This loop is white hot, so it
+           ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
+           ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
+           ;; call of `scan-lists' signals an error, which happens when there
+           ;; are no more b/b/p's to scan.
+           (c-safe
+             (while t
+               (setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
+                     paren+1s (cons pa+1 paren+1s))
+               (setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
+               (if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
+                   (setq bra+1 pa+1))
+               (setcar paren+1s ren+1)))
+
+           (if (and pa+1 (> pa+1 ren+1))
+               ;; We've just entered a deeper nesting level.
+               (progn
+                 ;; Insert the brace pair (if present) and the single open
+                 ;; paren/brace/bracket into `c-state-cache' It cannot be
+                 ;; inside a macro, except one around point, because of what
+                 ;; `c-neutralize-syntax-in-CPP' has done.
+                 (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+                 ;; Insert the opening brace/bracket/paren position.
+                 (setq c-state-cache (cons (1- pa+1) c-state-cache))
+                 ;; Clear admin stuff for the next more nested part of the scan.
+                 (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
+                 t)                    ; Carry on the loop
+
+             ;; All open p/b/b's at this nesting level, if any, have probably
+             ;; been closed by matching/mismatching ones.  We're probably
+             ;; finished - we just need to check for having found an
+             ;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
+             ;; macro, due the action of `c-neutralize-syntax-in-CPP'.
+             (c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
+
+      ;; Record the final, innermost, brace-pair if there is one.
+      (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+
+      ;; Determine a good pos
+      (while (and (setq paren+1 (car paren+1s))
+                 (> (if (> paren+1 macro-start-or-here)
+                        paren+1
+                      (goto-char paren+1)
+                      (setq mstart (and (c-beginning-of-macro)
+                                        (point)))
+                      (or mstart paren+1))
+                    here-bol))
+       (setq paren+1s (cdr paren+1s)))
+      (cond
+       ((and paren+1 mstart)
+       (min paren+1 mstart))
+       (paren+1)
+       (t from)))))
+
+(defun c-remove-stale-state-cache (good-pos pps-point)
+  ;; Remove stale entries from the `c-cache-state', i.e. those which will
+  ;; not be in it when it is amended for position (point-max).
+  ;; Additionally, the "outermost" open-brace entry before (point-max)
+  ;; will be converted to a cons if the matching close-brace is scanned.
+  ;;
+  ;; GOOD-POS is a "maximal" "safe position" - there must be no open
+  ;; parens/braces/brackets between GOOD-POS and (point-max).
+  ;;
+  ;; As a second thing, calculate the result of parse-partial-sexp at
+  ;; PPS-POINT, w.r.t. GOOD-POS.  The motivation here is that
+  ;; `c-state-cache-good-pos' may become PPS-POINT, but the caller may need to
+  ;; adjust it to get outside a string/comment.  (Sorry about this!  The code
+  ;; needs to be FAST).
+  ;;
+  ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
+  ;; o - GOOD-POS is a position where the new value `c-state-cache' is known
+  ;;   to be good (we aim for this to be as high as possible);
+  ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
+  ;;   preceding POS which needs to be recorded in `c-state-cache'.  It is a
+  ;;   position to scan backwards from.
+  ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
+  (save-restriction
+    (narrow-to-region 1 (point-max))
+    (save-excursion
+      (let* ((in-macro-start   ; start of macro containing (point-max) or nil.
+             (save-excursion
+               (goto-char (point-max))
+               (and (c-beginning-of-macro)
+                    (point))))
+            (good-pos-actual-macro-start ; Start of macro containing good-pos
+                                       ; or nil
+             (and (< good-pos (point-max))
+                  (save-excursion
+                    (goto-char good-pos)
+                    (and (c-beginning-of-macro)
+                         (point)))))
+            (good-pos-actual-macro-end ; End of this macro, (maybe
+                                       ; (point-max)), or nil.
+             (and good-pos-actual-macro-start
+                  (save-excursion
+                    (goto-char good-pos-actual-macro-start)
+                    (c-end-of-macro)
+                    (point))))
+            pps-state                  ; Will be 9 or 10 elements long.
+            pos
+            upper-lim     ; ,beyond which `c-state-cache' entries are removed
+            scan-back-pos
+            pair-beg pps-point-state target-depth)
+
+       ;; Remove entries beyond (point-max).  Also remove any entries inside
+       ;; a macro, unless (point-max) is in the same macro.
+       (setq upper-lim
+             (if (or (null c-state-old-cpp-beg)
+                     (and (> (point-max) c-state-old-cpp-beg)
+                          (< (point-max) c-state-old-cpp-end)))
+                 (point-max)
+               (min (point-max) c-state-old-cpp-beg)))
+       (while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
+         (setq c-state-cache (cdr c-state-cache)))
+       ;; If `upper-lim' is inside the last recorded brace pair, remove its
+       ;; RBrace and indicate we'll need to search backwards for a previous
+       ;; brace pair.
+       (when (and c-state-cache
+                  (consp (car c-state-cache))
+                  (> (cdar c-state-cache) upper-lim))
+         (setcar c-state-cache (caar c-state-cache))
+         (setq scan-back-pos (car c-state-cache)))
+
+       ;; The next loop jumps forward out of a nested level of parens each
+       ;; time round; the corresponding elements in `c-state-cache' are
+       ;; removed.  `pos' is just after the brace-pair or the open paren at
+       ;; (car c-state-cache).  There can be no open parens/braces/brackets
+       ;; between `good-pos'/`good-pos-actual-macro-start' and (point-max),
+       ;; due to the interface spec to this function.
+       (setq pos (if (and good-pos-actual-macro-end
+                          (not (eq good-pos-actual-macro-start
+                                   in-macro-start)))
+                     (1+ good-pos-actual-macro-end) ; get outside the macro as
+                                       ; marked by a `category' text property.
+                   good-pos))
+       (goto-char pos)
+       (while (and c-state-cache
+                   (< (point) (point-max)))
+         (cond
+          ((null pps-state)            ; first time through
+           (setq target-depth -1))
+          ((eq (car pps-state) target-depth) ; found closing ),},]
+           (setq target-depth (1- (car pps-state))))
+          ;; Do nothing when we've merely reached pps-point.
+          )
+
+         ;; Scan!
+         (setq pps-state
+               (parse-partial-sexp
+                (point) (if (< (point) pps-point) pps-point (point-max))
+                target-depth
+                nil pps-state))
+
+         (if (= (point) pps-point)
+             (setq pps-point-state pps-state))
+
+         (when (eq (car pps-state) target-depth)
+           (setq pos (point))       ; POS is now just after an R-paren/brace.
+           (cond
+            ((and (consp (car c-state-cache))
+                  (eq (point) (cdar c-state-cache)))
+               ;; We've just moved out of the paren pair containing the brace-pair
+               ;; at (car c-state-cache).  `pair-beg' is where the open paren is,
+               ;; and is potentially where the open brace of a cons in
+               ;; c-state-cache will be.
+             (setq pair-beg (car-safe (cdr c-state-cache))
+                   c-state-cache (cdr-safe (cdr c-state-cache)))) ; remove {}pair + containing Lparen.
+            ((numberp (car c-state-cache))
+             (setq pair-beg (car c-state-cache)
+                   c-state-cache (cdr c-state-cache))) ; remove this
+                                       ; containing Lparen
+            ((numberp (cadr c-state-cache))
+             (setq pair-beg (cadr c-state-cache)
+                   c-state-cache (cddr c-state-cache))) ; Remove a paren pair
+                                       ; together with enclosed brace pair.
+            ;; (t nil)                 ; Ignore an unmated Rparen.
+            )))
+
+       (if (< (point) pps-point)
+           (setq pps-state (parse-partial-sexp (point) pps-point
+                                               nil nil ; TARGETDEPTH, STOPBEFORE
+                                               pps-state)))
+
+       ;; If the last paren pair we moved out of was actually a brace pair,
+       ;; insert it into `c-state-cache'.
+       (when (and pair-beg (eq (char-after pair-beg) ?{))
+         (if (consp (car-safe c-state-cache))
+             (setq c-state-cache (cdr c-state-cache)))
+         (setq c-state-cache (cons (cons pair-beg pos)
+                                   c-state-cache)))
+
+       (list pos scan-back-pos pps-state)))))
+
+(defun c-remove-stale-state-cache-backwards (here cache-pos)
+  ;; Strip stale elements of `c-state-cache' by moving backwards through the
+  ;; buffer, and inform the caller of the scenario detected.
+  ;;
+  ;; HERE is the position we're setting `c-state-cache' for.
+  ;; CACHE-POS is just after the latest recorded position in `c-state-cache'
+  ;;   before HERE, or a position at or near point-min which isn't in a
+  ;;   literal.
+  ;;
+  ;; This function must only be called only when (> `c-state-cache-good-pos'
+  ;; HERE).  Usually the gap between CACHE-POS and HERE is large.  It is thus
+  ;; optimised to eliminate (or minimise) scanning between these two
+  ;; positions.
+  ;;
+  ;; Return a three element list (GOOD-POS SCAN-BACK-POS FWD-FLAG), where:
+  ;; o - GOOD-POS is a "good position", where `c-state-cache' is valid, or
+  ;;   could become so after missing elements are inserted into
+  ;;   `c-state-cache'.  This is JUST AFTER an opening or closing
+  ;;   brace/paren/bracket which is already in `c-state-cache' or just before
+  ;;   one otherwise.  exceptionally (when there's no such b/p/b handy) the BOL
+  ;;   before `here''s line, or the start of the literal containing it.
+  ;; o - SCAN-BACK-POS, if non-nil, indicates there may be a brace pair
+  ;;   preceding POS which isn't recorded in `c-state-cache'.  It is a position
+  ;;   to scan backwards from.
+  ;; o - FWD-FLAG, if non-nil, indicates there may be parens/braces between
+  ;;   POS and HERE which aren't recorded in `c-state-cache'.
+  ;;
+  ;; The comments in this defun use "paren" to mean parenthesis or square
+  ;; bracket (as contrasted with a brace), and "(" and ")" likewise.
+  ;;
+  ;;    .   {..} (..) (..)  ( .. {   }  ) (...)    ( ....          .  ..)
+  ;;    |                   |       |   |     |                    |
+  ;;    CP                  E      here D     C                   good
+  (let ((pos c-state-cache-good-pos)
+       pa ren         ; positions of "(" and ")"
+       dropped-cons ; whether the last element dropped from `c-state-cache'
+                    ; was a cons (representing a brace-pair)
+       good-pos                        ; see above.
+       lit         ; (START . END) of a literal containing some point.
+       here-lit-start here-lit-end     ; bounds of literal containing `here'
+                                       ; or `here' itself.
+       here- here+                  ; start/end of macro around HERE, or HERE
+       (here-bol (c-point 'bol here))
+       (too-far-back (max (- here c-state-cache-too-far) 1)))
+
+    ;; Remove completely irrelevant entries from `c-state-cache'.
+    (while (and c-state-cache
+               (>= (setq pa (c-state-cache-top-lparen)) here))
+      (setq dropped-cons (consp (car c-state-cache)))
+      (setq c-state-cache (cdr c-state-cache))
+      (setq pos pa))
+    ;; At this stage, (> pos here);
+    ;; (< (c-state-cache-top-lparen) here)  (or is nil).
+
+    (cond
+     ((and (consp (car c-state-cache))
+          (> (cdar c-state-cache) here))
+      ;; CASE 1: The top of the cache is a brace pair which now encloses
+      ;; `here'.  As good-pos, return the address. of the "{".  Since we've no
+      ;; knowledge of what's inside these braces, we have no alternative but
+      ;; to direct the caller to scan the buffer from the opening brace.
+      (setq pos (caar c-state-cache))
+      (setcar c-state-cache pos)
+      (list (1+ pos) pos t)) ; return value.  We've just converted a brace pair
+                            ; entry into a { entry, so the caller needs to
+                            ; search for a brace pair before the {.
+
+     ;; `here' might be inside a literal.  Check for this.
+     ((progn
+       (setq lit (c-state-literal-at here)
+             here-lit-start (or (car lit) here)
+             here-lit-end (or (cdr lit) here))
+       ;; Has `here' just "newly entered" a macro?
+       (save-excursion
+         (goto-char here-lit-start)
+         (if (and (c-beginning-of-macro)
+                  (or (null c-state-old-cpp-beg)
+                      (not (= (point) c-state-old-cpp-beg))))
+             (progn
+               (setq here- (point))
+               (c-end-of-macro)
+               (setq here+ (point)))
+           (setq here- here-lit-start
+                 here+ here-lit-end)))
+
+       ;; `here' might be nested inside any depth of parens (or brackets but
+       ;; not braces).  Scan backwards to find the outermost such opening
+       ;; paren, if there is one.  This will be the scan position to return.
+       (save-restriction
+         (narrow-to-region cache-pos (point-max))
+         (setq pos (c-state-balance-parens-backwards here- here+ pos)))
+       nil))                           ; for the cond
+
+     ((< pos here-lit-start)
+      ;; CASE 2: Address of outermost ( or [ which now encloses `here', but
+      ;; didn't enclose the (previous) `c-state-cache-good-pos'.  If there is
+      ;; a brace pair preceding this, it will already be in `c-state-cache',
+      ;; unless there was a brace pair after it, i.e. there'll only be one to
+      ;; scan for if we've just deleted one.
+      (list pos (and dropped-cons pos) t)) ; Return value.
+
+      ;; `here' isn't enclosed in a (previously unrecorded) bracket/paren.
+      ;; Further forward scanning isn't needed, but we still need to find a
+      ;; GOOD-POS.  Step out of all enclosing "("s on HERE's line.
+     ((progn
+       (save-restriction
+         (narrow-to-region here-bol (point-max))
+         (setq pos here-lit-start)
+         (c-safe (while (setq pa (scan-lists pos -1 1))
+                   (setq pos pa))))    ; might signal
+       nil))                           ; for the cond
+
+     ((setq ren (c-safe-scan-lists pos -1 -1 too-far-back))
+       ;; CASE 3: After a }/)/] before `here''s BOL.
+      (list (1+ ren) (and dropped-cons pos) nil)) ; Return value
+
+     (t
+      ;; CASE 4; Best of a bad job: BOL before `here-bol', or beginning of
+      ;; literal containing it.
+      (setq good-pos (c-state-lit-beg (c-point 'bopl here-bol)))
+      (list good-pos (and dropped-cons good-pos) nil)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Externally visible routines.
+
+(defun c-state-cache-init ()
+  (setq c-state-cache nil
+       c-state-cache-good-pos 1
+       c-state-nonlit-pos-cache nil
+       c-state-nonlit-pos-cache-limit 1
+       c-state-brace-pair-desert nil
+       c-state-point-min 1
+       c-state-point-min-lit-type nil
+       c-state-point-min-lit-start nil
+       c-state-min-scan-pos 1
+       c-state-old-cpp-beg nil
+       c-state-old-cpp-end nil)
+  (c-state-mark-point-min-literal))
+
+(defun c-invalidate-state-cache-1 (here)
+  ;; Invalidate all info on `c-state-cache' that applies to the buffer at HERE
+  ;; or higher and set `c-state-cache-good-pos' accordingly.  The cache is
+  ;; left in a consistent state.
+  ;;
+  ;; This is much like `c-whack-state-after', but it never changes a paren
+  ;; pair element into an open paren element.  Doing that would mean that the
+  ;; new open paren wouldn't have the required preceding paren pair element.
+  ;;
+  ;; This function is called from c-after-change.
+
+  ;; The cache of non-literals:
+  (if (< here c-state-nonlit-pos-cache-limit)
+      (setq c-state-nonlit-pos-cache-limit here))
+
+  ;; `c-state-cache':
+  ;; Case 1: if `here' is in a literal containing point-min, everything
+  ;; becomes (or is already) nil.
+  (if (or (null c-state-cache-good-pos)
+         (< here (c-state-get-min-scan-pos)))
+      (setq c-state-cache nil
+           c-state-cache-good-pos nil
+           c-state-min-scan-pos nil)
+
+;;; Truncate `c-state-cache' and set `c-state-cache-good-pos' to a value below
+;;; `here'.  To maintain its consistency, we may need to insert a new brace
+;;; pair.
+    (let ((here-bol (c-point 'bol here))
+         too-high-pa             ; recorded {/(/[ next above here, or nil.
+         dropped-cons            ; was the last removed element a brace pair?
+         pa)
+      ;; The easy bit - knock over-the-top bits off `c-state-cache'.
+      (while (and c-state-cache
+                 (>= (setq pa (c-state-cache-top-paren)) here))
+       (setq dropped-cons (consp (car c-state-cache))
+             too-high-pa (c-state-cache-top-lparen)
+             c-state-cache (cdr c-state-cache)))
+
+      ;; Do we need to add in an earlier brace pair, having lopped one off?
+      (if (and dropped-cons
+              (< too-high-pa (+ here c-state-cache-too-far)))
+         (c-append-lower-brace-pair-to-state-cache too-high-pa here-bol))
+      (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
+                                      (c-state-get-min-scan-pos)))))
+
+  ;; The brace-pair desert marker:
+  (when (car c-state-brace-pair-desert)
+    (if (< here (car c-state-brace-pair-desert))
+       (setq c-state-brace-pair-desert nil)
+      (if (< here (cdr c-state-brace-pair-desert))
+         (setcdr c-state-brace-pair-desert here)))))
+
+(defun c-parse-state-1 ()
+  ;; Find and record all noteworthy parens between some good point earlier in
+  ;; the file and point.  That good point is at least the beginning of the
+  ;; top-level construct we are in, or the beginning of the preceding
+  ;; top-level construct if we aren't in one.
+  ;;
+  ;; The returned value is a list of the noteworthy parens with the last one
+  ;; first.  If an element in the list is an integer, it's the position of an
+  ;; open paren (of any type) which has not been closed before the point.  If
+  ;; an element is a cons, it gives the position of a closed BRACE paren
+  ;; pair[*]; the car is the start brace position and the cdr is the position
+  ;; following the closing brace.  Only the last closed brace paren pair
+  ;; before each open paren and before the point is recorded, and thus the
+  ;; state never contains two cons elements in succession.  When a close brace
+  ;; has no matching open brace (e.g., the matching brace is outside the
+  ;; visible region), it is not represented in the returned value.
+  ;;
+  ;; [*] N.B. The close "brace" might be a mismatching close bracket or paren.
+  ;; This defun explicitly treats mismatching parens/braces/brackets as
+  ;; matching.  It is the open brace which makes it a "brace" pair.
+  ;;
+  ;; If POINT is within a macro, open parens and brace pairs within
+  ;; THIS macro MIGHT be recorded.  This depends on whether their
+  ;; syntactic properties have been suppressed by
+  ;; `c-neutralize-syntax-in-CPP'.  This might need fixing (2008-12-11).
   ;;
   ;; Currently no characters which are given paren syntax with the
   ;; syntax-table property are recorded, i.e. angle bracket arglist
   ;; parens are never present here.  Note that this might change.
   ;;
   ;; BUG: This function doesn't cope entirely well with unbalanced
-  ;; parens in macros.  E.g. in the following case the brace before
-  ;; the macro isn't balanced with the one after it:
+  ;; parens in macros.  (2008-12-11: this has probably been resolved
+  ;; by the function `c-neutralize-syntax-in-CPP'.)  E.g. in the
+  ;; following case the brace before the macro isn't balanced with the
+  ;; one after it:
   ;;
   ;;     {
   ;;     #define X {
   ;;     }
   ;;
+  ;; Note to maintainers: this function DOES get called with point
+  ;; within comments and strings, so don't assume it doesn't!
+  ;;
   ;; This function might do hidden buffer changes.
+  (let* ((here (point))
+        (here-bopl (c-point 'bopl))
+        strategy            ; 'forward, 'backward etc..
+        ;; Candidate positions to start scanning from:
+        cache-pos           ; highest position below HERE already existing in
+                            ; cache (or 1).
+        good-pos
+        start-point
+        bopl-state
+        res
+        scan-backward-pos scan-forward-p) ; used for 'backward.
+    ;; If POINT-MIN has changed, adjust the cache
+    (unless (= (point-min) c-state-point-min)
+      (c-renarrow-state-cache))
+
+    ;; Strategy?
+    (setq res (c-parse-state-get-strategy here c-state-cache-good-pos)
+         strategy (car res)
+         cache-pos (cadr res)
+         start-point (nth 2 res))
+
+    (when (eq strategy 'BOD)
+      (setq c-state-cache nil
+           c-state-cache-good-pos start-point))
+
+    ;; SCAN!
+    (save-restriction
+      (cond
+       ((memq strategy '(forward BOD))
+       (narrow-to-region (point-min) here)
+       (setq res (c-remove-stale-state-cache start-point here-bopl))
+       (setq cache-pos (car res)
+             scan-backward-pos (cadr res)
+             bopl-state (car (cddr res))) ; will be nil if (< here-bopl
+                                       ; start-point)
+       (if scan-backward-pos
+           (c-append-lower-brace-pair-to-state-cache scan-backward-pos))
+       (setq good-pos
+             (c-append-to-state-cache cache-pos))
+       (setq c-state-cache-good-pos
+             (if (and bopl-state
+                      (< good-pos (- here c-state-cache-too-far)))
+                 (c-state-cache-non-literal-place here-bopl bopl-state)
+               good-pos)))
+
+       ((eq strategy 'backward)
+       (setq res (c-remove-stale-state-cache-backwards here cache-pos)
+             good-pos (car res)
+             scan-backward-pos (cadr res)
+             scan-forward-p (car (cddr res)))
+       (if scan-backward-pos
+           (c-append-lower-brace-pair-to-state-cache
+            scan-backward-pos))
+       (setq c-state-cache-good-pos
+             (if scan-forward-p
+                 (progn (narrow-to-region (point-min) here)
+                        (c-append-to-state-cache good-pos))
+
+               (c-get-cache-scan-pos good-pos))))
+
+       (t ; (eq strategy 'IN-LIT)
+       (setq c-state-cache nil
+             c-state-cache-good-pos nil)))))
+
+  c-state-cache)
+
+(defun c-invalidate-state-cache (here)
+  ;; This is a wrapper over `c-invalidate-state-cache-1'.
+  ;;
+  ;; It suppresses the syntactic effect of the < and > (template) brackets and
+  ;; of all parens in preprocessor constructs, except for any such construct
+  ;; containing point.  We can then call `c-invalidate-state-cache-1' without
+  ;; worrying further about macros and template delimiters.
+  (c-with-<->-as-parens-suppressed
+   (if (and c-state-old-cpp-beg
+           (< c-state-old-cpp-beg here))
+       (c-with-all-but-one-cpps-commented-out
+       c-state-old-cpp-beg
+       (min c-state-old-cpp-end here)
+       (c-invalidate-state-cache-1 here))
+     (c-with-cpps-commented-out
+      (c-invalidate-state-cache-1 here)))))
 
-  (save-restriction
-    (let* ((here (point))
-          (here-bol (c-point 'bol))
-          (c-macro-start (c-query-macro-start))
-          (in-macro-start (or c-macro-start (point)))
-          old-state last-pos brace-pair-open brace-pair-close
-          pos save-pos)
-      (c-invalidate-state-cache here)
-
-      ;; If the minimum position has changed due to narrowing then we
-      ;; have to fix the tail of `c-state-cache' accordingly.
-      (unless (= c-state-cache-start (point-min))
-       (if (> (point-min) c-state-cache-start)
-           ;; If point-min has moved forward then we just need to cut
-           ;; off a bit of the tail.
-           (let ((ptr (cons nil c-state-cache)) elem)
-             (while (and (setq elem (car-safe (cdr ptr)))
-                         (>= (if (consp elem) (car elem) elem)
-                             (point-min)))
-               (setq ptr (cdr ptr)))
-             (when (consp ptr)
-               (if (eq (cdr ptr) c-state-cache)
-                   (setq c-state-cache nil
-                         c-state-cache-good-pos 1)
-                 (setcdr ptr nil))))
-         ;; If point-min has moved backward then we drop the state
-         ;; completely.  It's possible to do a better job here and
-         ;; recalculate the top only.
-         (setq c-state-cache nil
-               c-state-cache-good-pos 1))
-       (setq c-state-cache-start (point-min)))
-
-      ;; Get the latest position we know are directly inside the
-      ;; closest containing paren of the cached state.
-      (setq last-pos (and c-state-cache
-                         (if (consp (car c-state-cache))
-                             (cdr (car c-state-cache))
-                           (1+ (car c-state-cache)))))
-      (if (or (not last-pos)
-             (< last-pos c-state-cache-good-pos))
-         (setq last-pos c-state-cache-good-pos)
-       ;; Take the opportunity to move the cached good position
-       ;; further down.
-       (if (< last-pos here-bol)
-           (setq c-state-cache-good-pos last-pos)))
+(defun c-parse-state ()
+  ;; This is a wrapper over `c-parse-state-1'.  See that function for a
+  ;; description of the functionality and return value.
+  ;;
+  ;; It suppresses the syntactic effect of the < and > (template) brackets and
+  ;; of all parens in preprocessor constructs, except for any such construct
+  ;; containing point.  We can then call `c-parse-state-1' without worrying
+  ;; further about macros and template delimiters.
+  (let (here-cpp-beg here-cpp-end)
+    (save-excursion
+      (when (c-beginning-of-macro)
+       (setq here-cpp-beg (point))
+       (unless
+           (> (setq here-cpp-end (c-syntactic-end-of-macro))
+              here-cpp-beg)
+         (setq here-cpp-beg nil  here-cpp-end nil))))
+    ;; FIXME!!! Put in a `condition-case' here to protect the integrity of the
+    ;; subsystem.
+    (prog1
+       (c-with-<->-as-parens-suppressed
+        (if (and here-cpp-beg (> here-cpp-end here-cpp-beg))
+            (c-with-all-but-one-cpps-commented-out
+             here-cpp-beg here-cpp-end
+             (c-parse-state-1))
+          (c-with-cpps-commented-out
+           (c-parse-state-1))))
+      (setq c-state-old-cpp-beg (and here-cpp-beg (copy-marker here-cpp-beg t))
+           c-state-old-cpp-end (and here-cpp-end (copy-marker here-cpp-end t)))
+      )))
 
-      ;; Check if `last-pos' is in a macro.  If it is, and we're not
-      ;; in the same macro, we must discard everything on
-      ;; `c-state-cache' that is inside the macro before using it.
-      (save-excursion
-       (goto-char last-pos)
-       (when (and (c-beginning-of-macro)
-                  (/= (point) in-macro-start))
-         (c-invalidate-state-cache (point))
-         ;; Set `last-pos' again just like above except that there's
-         ;; no use looking at `c-state-cache-good-pos' here.
-         (setq last-pos (if c-state-cache
-                            (if (consp (car c-state-cache))
-                                (cdr (car c-state-cache))
-                              (1+ (car c-state-cache)))
-                          1))))
-
-      ;; If we've moved very far from the last cached position then
-      ;; it's probably better to redo it from scratch, otherwise we
-      ;; might spend a lot of time searching from `last-pos' down to
-      ;; here.
-      (when (< last-pos (- here 20000))
-       ;; First get the fallback start position.  If it turns out
-       ;; that it's so far back that the cached state is closer then
-       ;; we'll keep it afterall.
-       (setq pos (c-get-fallback-start-pos here))
-       (if (<= pos last-pos)
-           (setq pos nil)
-         (setq last-pos nil
-               c-state-cache nil
-               c-state-cache-good-pos 1)))
-
-      ;; Find the start position for the forward search.  (Can't
-      ;; search in the backward direction since the point might be in
-      ;; some kind of literal.)
-
-      (unless pos
-       (setq old-state c-state-cache)
-
-       ;; There's a cached state with a containing paren.  Pop off
-       ;; the stale containing sexps from it by going forward out of
-       ;; parens as far as possible.
-       (narrow-to-region (point-min) here)
-       (let (placeholder pair-beg)
-         (while (and c-state-cache
-                     (setq placeholder
-                           (c-up-list-forward last-pos)))
-           (setq last-pos placeholder)
-           (if (consp (car c-state-cache))
-               (setq pair-beg (car-safe (cdr c-state-cache))
-                     c-state-cache (cdr-safe (cdr c-state-cache)))
-             (setq pair-beg (car c-state-cache)
-                   c-state-cache (cdr c-state-cache))))
-
-         (when (and pair-beg (eq (char-after pair-beg) ?{))
-           ;; The last paren pair we moved out from was a brace
-           ;; pair.  Modify the state to record this as a closed
-           ;; pair now.
-           (if (consp (car-safe c-state-cache))
-               (setq c-state-cache (cdr c-state-cache)))
-           (setq c-state-cache (cons (cons pair-beg last-pos)
-                                     c-state-cache))))
-
-       ;; Check if the preceding balanced paren is within a
-       ;; macro; it should be ignored if we're outside the
-       ;; macro.  There's no need to check any further upwards;
-       ;; if the macro contains an unbalanced opening paren then
-       ;; we're smoked anyway.
-       (when (and (<= (point) in-macro-start)
-                  (consp (car c-state-cache)))
-         (save-excursion
-           (goto-char (car (car c-state-cache)))
-           (when (c-beginning-of-macro)
-             (setq here (point)
-                   c-state-cache (cdr c-state-cache)))))
-
-       (unless (eq c-state-cache old-state)
-         ;; Have to adjust the cached good position if state has been
-         ;; popped off.
-         (setq c-state-cache-good-pos
-               (if c-state-cache
-                   (if (consp (car c-state-cache))
-                       (cdr (car c-state-cache))
-                     (1+ (car c-state-cache)))
-                 1)
-               old-state c-state-cache))
-
-       (when c-state-cache
-         (setq pos last-pos)))
-
-      ;; Get the fallback start position.
-      (unless pos
-       (setq pos (c-get-fallback-start-pos here)
-             c-state-cache nil
-             c-state-cache-good-pos 1))
-
-      (narrow-to-region (point-min) here)
-
-      (while pos
-       (setq save-pos pos
-             brace-pair-open nil)
-
-       ;; Find the balanced brace pairs.  This loop is hot, so it
-       ;; does ugly tricks to go faster.
-       (c-safe
-         (let (set-good-pos set-brace-pair)
-           (while t
-             (setq last-pos nil
-                   last-pos (scan-lists pos 1 -1)) ; Might signal.
-             (setq pos (scan-lists last-pos 1 1) ; Might signal.
-                   set-good-pos (< pos here-bol)
-                   set-brace-pair (eq (char-before last-pos) ?{))
-
-             ;; Update the cached good position and record the brace
-             ;; pair, whichever is applicable for the paren we've
-             ;; just jumped over.  But first check that it isn't
-             ;; inside a macro and the point isn't inside the same
-             ;; one.
-             (when (and (or set-good-pos set-brace-pair)
-                        (or (>= pos in-macro-start)
-                            (save-excursion
-                              (goto-char pos)
-                              (not (c-beginning-of-macro)))))
-               (if set-good-pos
-                   (setq c-state-cache-good-pos pos))
-               (if set-brace-pair
-                   (setq brace-pair-open last-pos
-                         brace-pair-close pos))))))
-
-       ;; Record the last brace pair.
-       (when brace-pair-open
-         (let ((head (car-safe c-state-cache)))
-           (if (consp head)
-               (progn
-                 (setcar head (1- brace-pair-open))
-                 (setcdr head brace-pair-close))
-             (setq c-state-cache (cons (cons (1- brace-pair-open)
-                                             brace-pair-close)
-                                       c-state-cache)))))
-
-       (if last-pos
-           ;; Prepare to loop, but record the open paren only if it's
-           ;; outside a macro or within the same macro as point, and
-           ;; if it is a legitimate open paren and not some character
-           ;; that got an open paren syntax-table property.
-           (progn
-             (setq pos last-pos)
-             (when (and (or (>= last-pos in-macro-start)
-                            (save-excursion
-                              (goto-char last-pos)
-                              (not (c-beginning-of-macro))))
-                        ;; Check for known types of parens that we
-                        ;; want to record.  The syntax table is not to
-                        ;; be trusted here since the caller might be
-                        ;; using e.g. `c++-template-syntax-table'.
-                        (memq (char-before last-pos) '(?{ ?\( ?\[)))
-               (if (< last-pos here-bol)
-                   (setq c-state-cache-good-pos last-pos))
-               (setq c-state-cache (cons (1- last-pos) c-state-cache))))
-
-         (if (setq last-pos (c-up-list-forward pos))
-             ;; Found a close paren without a corresponding opening
-             ;; one.  Maybe we didn't go back far enough, so try to
-             ;; scan backward for the start paren and then start over.
-             (progn
-               (setq pos (c-up-list-backward pos)
-                     c-state-cache nil
-                     c-state-cache-good-pos c-state-cache-start)
-               (when (or (not pos)
-                         ;; Emacs (up to at least 21.2) can get confused by
-                         ;; open parens in column zero inside comments: The
-                         ;; sexp functions can then misbehave and bring us
-                         ;; back to the same point again.  Check this so that
-                         ;; we don't get an infinite loop.
-                         (>= pos save-pos))
-                 (setq pos last-pos
-                       c-parsing-error
-                       (format "Unbalanced close paren at line %d"
-                               (1+ (count-lines (point-min)
-                                                (c-point 'bol last-pos)))))))
-           (setq pos nil))))
-
-      ;;(message "c-parse-state: %S end: %S" c-state-cache c-state-cache-good-pos)
-      c-state-cache)))
-
-;; Debug tool to catch cache inconsistencies.
+;; Debug tool to catch cache inconsistencies.  This is called from
+;; 000tests.el.
 (defvar c-debug-parse-state nil)
 (unless (fboundp 'c-real-parse-state)
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 (defun c-debug-parse-state ()
-  (let ((res1 (c-real-parse-state)) res2)
+  (let ((here (point)) (res1 (c-real-parse-state)) res2)
     (let ((c-state-cache nil)
-         (c-state-cache-start 1)
-         (c-state-cache-good-pos 1))
+         (c-state-cache-good-pos 1)
+         (c-state-nonlit-pos-cache nil)
+         (c-state-nonlit-pos-cache-limit 1)
+         (c-state-brace-pair-desert nil)
+         (c-state-point-min 1)
+         (c-state-point-min-lit-type nil)
+         (c-state-point-min-lit-start nil)
+         (c-state-min-scan-pos 1)
+         (c-state-old-cpp-beg nil)
+         (c-state-old-cpp-end nil))
       (setq res2 (c-real-parse-state)))
     (unless (equal res1 res2)
       ;; The cache can actually go further back due to the ad-hoc way
@@ -2289,10 +3084,11 @@ comment at the start of cc-engine.el for more info."
        (while (not (or (bobp) (eq (char-after) ?{)))
          (c-beginning-of-defun-1))
        (unless (equal (c-whack-state-before (point) res1) res2)
-         (message (concat "c-parse-state inconsistency: "
+         (message (concat "c-parse-state inconsistency at %s: "
                           "using cache: %s, from scratch: %s")
-                  res1 res2))))
+                  here res1 res2))))
     res1))
+
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")
   (setq c-debug-parse-state (c-calculate-state arg c-debug-parse-state))
@@ -2303,6 +3099,7 @@ comment at the start of cc-engine.el for more info."
 (when c-debug-parse-state
   (c-toggle-parse-state-debug 1))
 
+\f
 (defun c-whack-state-before (bufpos paren-state)
   ;; Whack off any state information from PAREN-STATE which lies
   ;; before BUFPOS.  Not destructive on PAREN-STATE.
@@ -2968,6 +3765,59 @@ comment at the start of cc-engine.el for more info."
        (goto-char bound))
       nil)))
 
+(defvar safe-pos-list)           ; bound in c-syntactic-skip-backward
+
+(defsubst c-ssb-lit-begin ()
+  ;; Return the start of the literal point is in, or nil.
+  ;; We read and write the variables `safe-pos', `safe-pos-list', `state'
+  ;; bound in the caller.
+
+  ;; Use `parse-partial-sexp' from a safe position down to the point to check
+  ;; if it's outside comments and strings.
+  (save-excursion
+    (let ((pos (point)) safe-pos state pps-end-pos)
+      ;; Pick a safe position as close to the point as possible.
+      ;;
+      ;; FIXME: Consult `syntax-ppss' here if our cache doesn't give a good
+      ;; position.
+
+      (while (and safe-pos-list
+                 (> (car safe-pos-list) (point)))
+       (setq safe-pos-list (cdr safe-pos-list)))
+      (unless (setq safe-pos (car-safe safe-pos-list))
+       (setq safe-pos (max (or (c-safe-position
+                                (point) (or c-state-cache
+                                            (c-parse-state)))
+                               0)
+                           (point-min))
+             safe-pos-list (list safe-pos)))
+
+      ;; Cache positions along the way to use if we have to back up more.  We
+      ;; cache every closing paren on the same level.  If the paren cache is
+      ;; relevant in this region then we're typically already on the same
+      ;; level as the target position.  Note that we might cache positions
+      ;; after opening parens in case safe-pos is in a nested list.  That's
+      ;; both uncommon and harmless.
+      (while (progn
+              (setq state (parse-partial-sexp
+                           safe-pos pos 0))
+              (< (point) pos))
+       (setq safe-pos (point)
+             safe-pos-list (cons safe-pos safe-pos-list)))
+
+      ;; If the state contains the start of the containing sexp we cache that
+      ;; position too, so that parse-partial-sexp in the next run has a bigger
+      ;; chance of starting at the same level as the target position and thus
+      ;; will get more good safe positions into the list.
+      (if (elt state 1)
+         (setq safe-pos (1+ (elt state 1))
+               safe-pos-list (cons safe-pos safe-pos-list)))
+
+      (if (or (elt state 3) (elt state 4))
+         ;; Inside string or comment.  Continue search at the
+         ;; beginning of it.
+         (elt state 8)))))
+
 (defun c-syntactic-skip-backward (skip-chars &optional limit paren-level)
   "Like `skip-chars-backward' but only look at syntactically relevant chars,
 i.e. don't stop at positions inside syntactic whitespace or string
@@ -2986,140 +3836,100 @@ Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
 
   (let ((start (point))
-       state
+       state-2
        ;; A list of syntactically relevant positions in descending
        ;; order.  It's used to avoid scanning repeatedly over
        ;; potentially large regions with `parse-partial-sexp' to verify
-       ;; each position.
+       ;; each position.  Used in `c-ssb-lit-begin'
        safe-pos-list
-       ;; The position at the beginning of `safe-pos-list'.
-       safe-pos
        ;; The result from `c-beginning-of-macro' at the start position or the
        ;; start position itself if it isn't within a macro.  Evaluated on
        ;; demand.
        start-macro-beg
        ;; The earliest position after the current one with the same paren
        ;; level.  Used only when `paren-level' is set.
+       lit-beg
        (paren-level-pos (point)))
 
-    (while (progn
-            (while (and
-                    (< (skip-chars-backward skip-chars limit) 0)
-
-                    ;; Use `parse-partial-sexp' from a safe position down to
-                    ;; the point to check if it's outside comments and
-                    ;; strings.
-                    (let ((pos (point)) state-2 pps-end-pos)
-                      ;; Pick a safe position as close to the point as
-                      ;; possible.
-                      ;;
-                      ;; FIXME: Consult `syntax-ppss' here if our
-                      ;; cache doesn't give a good position.
-                      (while (and safe-pos-list
-                                  (> (car safe-pos-list) (point)))
-                        (setq safe-pos-list (cdr safe-pos-list)))
-                      (unless (setq safe-pos (car-safe safe-pos-list))
-                        (setq safe-pos (max (or (c-safe-position
-                                                 (point) (or c-state-cache
-                                                             (c-parse-state)))
-                                                0)
-                                            (point-min))
-                              safe-pos-list (list safe-pos)))
-
-                      ;; Cache positions along the way to use if we have to
-                      ;; back up more.  We cache every closing paren on the
-                      ;; same level.  If the paren cache is relevant in this
-                      ;; region then we're typically already on the same
-                      ;; level as the target position.  Note that we might
-                      ;; cache positions after opening parens in case
-                      ;; safe-pos is in a nested list.  That's both uncommon
-                      ;; and harmless.
-                      (while (progn
-                               (setq state (parse-partial-sexp
-                                            safe-pos pos 0))
-                               (< (point) pos))
-                        (setq safe-pos (point)
-                              safe-pos-list (cons safe-pos safe-pos-list)))
-
-                      (cond
-                       ((or (elt state 3) (elt state 4))
-                        ;; Inside string or comment.  Continue search at the
-                        ;; beginning of it.
-                        (goto-char (elt state 8))
-                        t)
-
-                       ((and paren-level
-                             (save-excursion
-                               (setq state-2 (parse-partial-sexp
-                                              pos paren-level-pos -1)
-                                     pps-end-pos (point))
-                               (/= (car state-2) 0)))
-                        ;; Not at the right level.
-
-                        (if (and (< (car state-2) 0)
-                                 ;; We stop above if we go out of a paren.
-                                 ;; Now check whether it precedes or is
-                                 ;; nested in the starting sexp.
-                                 (save-excursion
-                                   (setq state-2
-                                         (parse-partial-sexp
-                                          pps-end-pos paren-level-pos
-                                          nil nil state-2))
-                                   (< (car state-2) 0)))
-
-                            ;; We've stopped short of the starting position
-                            ;; so the hit was inside a nested list.  Go up
-                            ;; until we are at the right level.
-                            (condition-case nil
+    (while
+       (progn
+         ;; The next loop "tries" to find the end point each time round,
+         ;; loops when it hasn't succeeded.
+         (while
+             (and
+              (< (skip-chars-backward skip-chars limit) 0)
+
+              (let ((pos (point)) state-2 pps-end-pos)
+
+                (cond
+                 ;; Don't stop inside a literal
+                 ((setq lit-beg (c-ssb-lit-begin))
+                  (goto-char lit-beg)
+                  t)
+
+                 ((and paren-level
+                       (save-excursion
+                         (setq state-2 (parse-partial-sexp
+                                        pos paren-level-pos -1)
+                               pps-end-pos (point))
+                         (/= (car state-2) 0)))
+                  ;; Not at the right level.
+
+                  (if (and (< (car state-2) 0)
+                           ;; We stop above if we go out of a paren.
+                           ;; Now check whether it precedes or is
+                           ;; nested in the starting sexp.
+                           (save-excursion
+                             (setq state-2
+                                   (parse-partial-sexp
+                                    pps-end-pos paren-level-pos
+                                    nil nil state-2))
+                             (< (car state-2) 0)))
+
+                      ;; We've stopped short of the starting position
+                      ;; so the hit was inside a nested list.  Go up
+                      ;; until we are at the right level.
+                      (condition-case nil
+                          (progn
+                            (goto-char (scan-lists pos -1
+                                                   (- (car state-2))))
+                            (setq paren-level-pos (point))
+                            (if (and limit (>= limit paren-level-pos))
                                 (progn
-                                  (goto-char (scan-lists pos -1
-                                                         (- (car state-2))))
-                                  (setq paren-level-pos (point))
-                                  (if (and limit (>= limit paren-level-pos))
-                                      (progn
-                                        (goto-char limit)
-                                        nil)
-                                    t))
-                              (error
-                               (goto-char (or limit (point-min)))
-                               nil))
-
-                          ;; The hit was outside the list at the start
-                          ;; position.  Go to the start of the list and exit.
-                          (goto-char (1+ (elt state-2 1)))
-                          nil))
-
-                       ((c-beginning-of-macro limit)
-                        ;; Inside a macro.
-                        (if (< (point)
-                               (or start-macro-beg
-                                   (setq start-macro-beg
-                                         (save-excursion
-                                           (goto-char start)
-                                           (c-beginning-of-macro limit)
-                                           (point)))))
-                            t
-
-                          ;; It's inside the same macro we started in so it's
-                          ;; a relevant match.
-                          (goto-char pos)
-                          nil)))))
-
-              ;; If the state contains the start of the containing sexp we
-              ;; cache that position too, so that parse-partial-sexp in the
-              ;; next run has a bigger chance of starting at the same level
-              ;; as the target position and thus will get more good safe
-              ;; positions into the list.
-              (if (elt state 1)
-                  (setq safe-pos (1+ (elt state 1))
-                        safe-pos-list (cons safe-pos safe-pos-list))))
-
-            (> (point)
-               (progn
-                 ;; Skip syntactic ws afterwards so that we don't stop at the
-                 ;; end of a comment if `skip-chars' is something like "^/".
-                 (c-backward-syntactic-ws)
-                 (point)))))
+                                  (goto-char limit)
+                                  nil)
+                              t))
+                        (error
+                         (goto-char (or limit (point-min)))
+                         nil))
+
+                    ;; The hit was outside the list at the start
+                    ;; position.  Go to the start of the list and exit.
+                    (goto-char (1+ (elt state-2 1)))
+                    nil))
+
+                 ((c-beginning-of-macro limit)
+                  ;; Inside a macro.
+                  (if (< (point)
+                         (or start-macro-beg
+                             (setq start-macro-beg
+                                   (save-excursion
+                                     (goto-char start)
+                                     (c-beginning-of-macro limit)
+                                     (point)))))
+                      t
+
+                    ;; It's inside the same macro we started in so it's
+                    ;; a relevant match.
+                    (goto-char pos)
+                    nil))))))
+            
+         (> (point)
+            (progn
+              ;; Skip syntactic ws afterwards so that we don't stop at the
+              ;; end of a comment if `skip-chars' is something like "^/".
+              (c-backward-syntactic-ws)
+              (point)))))
 
     ;; We might want to extend this with more useful return values in
     ;; the future.
@@ -3606,7 +4416,7 @@ comment at the start of cc-engine.el for more info."
   ;;    `c-decl-prefix-or-start-re' when that submatch matches.
   ;; o  The start of each `c-decl-prefix-or-start-re' match when
   ;;    submatch 1 doesn't match.
-  ;; o  The first token after the end of each occurence of the
+  ;; o  The first token after the end of each occurrence of the
   ;;    `c-type' text property with the value `c-decl-end', provided
   ;;    `c-type-decl-end-used' is set.
   ;;
@@ -4089,7 +4899,168 @@ comment at the start of cc-engine.el for more info."
        )))
 
 \f
-;; Handling of small scale constructs like types and names.
+;; Setting and removing syntax properties on < and > in languages (C++
+;; and Java) where they can be template/generic delimiters as well as
+;; their normal meaning of "less/greater than".
+
+;; Normally, < and > have syntax 'punctuation'.  When they are found to
+;; be delimiters, they are marked as such with the category properties
+;; c-<-as-paren-syntax, c->-as-paren-syntax respectively.
+
+;; STRATEGY:
+;;
+;; It is impossible to determine with certainty whether a <..> pair in
+;; C++ is two comparison operators or is template delimiters, unless
+;; one duplicates a lot of a C++ compiler.  For example, the following
+;; code fragment:
+;;
+;;     foo (a < b, c > d) ;
+;;
+;; could be a function call with two integer parameters (each a
+;; relational expression), or it could be a constructor for class foo
+;; taking one parameter d of templated type "a < b, c >".  They are
+;; somewhat easier to distinguish in Java.
+;;
+;; The strategy now (2010-01) adopted is to mark and unmark < and
+;; > IN MATCHING PAIRS ONLY.  [Previously, they were marked
+;; individually when their context so indicated.  This gave rise to
+;; intractible problems when one of a matching pair was deleted, or
+;; pulled into a literal.]
+;;
+;; At each buffer change, the syntax-table properties are removed in a
+;; before-change function and reapplied, when needed, in an
+;; after-change function.  It is far more important that the
+;; properties get removed when they they are spurious than that they
+;; be present when wanted.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun c-clear-<-pair-props (&optional pos)
+  ;; POS (default point) is at a < character.  If it is marked with
+  ;; open paren syntax-table text property, remove the property,
+  ;; together with the close paren property on the matching > (if
+  ;; any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (equal (c-get-char-property (1- (point)) 'syntax-table)
+                  c->-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (1- (point)) 'category))
+      (c-clear-char-property pos 'category))))
+
+(defun c-clear->-pair-props (&optional pos)
+  ;; POS (default point) is at a > character.  If it is marked with
+  ;; close paren syntax-table property, remove the property, together
+  ;; with the open paren property on the matching < (if any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (point) 'category))
+      (c-clear-char-property pos 'category))))
+
+(defun c-clear-<>-pair-props (&optional pos)
+  ;; POS (default point) is at a < or > character.  If it has an
+  ;; open/close paren syntax-table property, remove this property both
+  ;; from the current character and its partner (which will also be
+  ;; thusly marked).
+  (cond
+   ((eq (char-after) ?\<)
+    (c-clear-<-pair-props pos))
+   ((eq (char-after) ?\>)
+    (c-clear->-pair-props pos))
+   (t (c-benign-error
+       "c-clear-<>-pair-props called from wrong position"))))
+
+(defun c-clear-<-pair-props-if-match-after (lim &optional pos)
+  ;; POS (default point) is at a < character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching >
+  ;; (also marked) which is after LIM, remove the property both from
+  ;; the current > and its partner.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (and (>= (point) lim)
+                (equal (c-get-char-property (1- (point)) 'syntax-table)
+                       c->-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (1- (point)))
+       (c-unmark-<->-as-paren pos)))))
+
+(defun c-clear->-pair-props-if-match-before (lim &optional pos)
+  ;; POS (default point) is at a > character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching <
+  ;; (also marked) which is before LIM, remove the property both from
+  ;; the current < and its partner.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (and (<= (point) lim)
+                (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (point))
+       (c-unmark-<->-as-paren pos)))))
+
+(defun c-before-change-check-<>-operators (beg end)
+  ;; Unmark certain pairs of "< .... >" which are currently marked as
+  ;; template/generic delimiters.  (This marking is via syntax-table
+  ;; text properties).
+  ;;
+  ;; These pairs are those which are in the current "statement" (i.e.,
+  ;; the region between the {, }, or ; before BEG and the one after
+  ;; END), and which enclose any part of the interval (BEG END).
+  ;;
+  ;; Note that in C++ (?and Java), template/generic parens cannot
+  ;; enclose a brace or semicolon, so we use these as bounds on the
+  ;; region we must work on.
+  ;;
+  ;; This function is called from before-change-functions (via
+  ;; c-get-state-before-change-functions).  Thus the buffer is widened,
+  ;; and point is undefined, both at entry and exit.
+  ;;
+  ;; FIXME!!!  This routine ignores the possibility of macros entirely.
+  ;; 2010-01-29.
+  (save-excursion
+    (let ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
+         (end-lit-limits (progn (goto-char end) (c-literal-limits))))
+      ;; Locate the barrier before the changed region
+      (goto-char  (if beg-lit-limits (car beg-lit-limits) beg))
+      (c-syntactic-skip-backward "^;{}" (max (- beg 2048) (point-min)))
+
+      ;; Remove the syntax-table properties from each pertinent <...> pair.
+      ;; Firsly, the ones with the < before beg and > after beg.
+      (while (c-search-forward-char-property 'category 'c-<-as-paren-syntax beg)
+       (c-clear-<-pair-props-if-match-after beg (1- (point))))
+
+      ;; Locate the barrier after END.
+      (goto-char (if end-lit-limits (cdr end-lit-limits) end))
+      (c-syntactic-re-search-forward "[;{}]"
+                                    (min (+ end 2048) (point-max)) 'end)
+
+      ;; Remove syntax-table properties from the remaining pertinent <...>
+      ;; pairs, those with a > after end and < before end.
+      (while (c-search-backward-char-property 'category 'c->-as-paren-syntax end)
+       (c-clear->-pair-props-if-match-before end)))))
+
+
 
 (defun c-after-change-check-<>-operators (beg end)
   ;; This is called from `after-change-functions' when
@@ -4111,7 +5082,7 @@ comment at the start of cc-engine.el for more info."
                 (< beg (setq beg (match-end 0))))
        (while (progn (skip-chars-forward "^<>" beg)
                      (< (point) beg))
-         (c-clear-char-property (point) 'syntax-table)
+         (c-clear-<>-pair-props)
          (forward-char))))
 
     (when (< beg end)
@@ -4126,9 +5097,13 @@ comment at the start of cc-engine.el for more info."
                   (< end (setq end (match-end 0))))
          (while (progn (skip-chars-forward "^<>" end)
                        (< (point) end))
-           (c-clear-char-property (point) 'syntax-table)
+           (c-clear-<>-pair-props)
            (forward-char)))))))
 
+
+\f
+;; Handling of small scale constructs like types and names.
+
 ;; Dynamically bound variable that instructs `c-forward-type' to also
 ;; treat possible types (i.e. those that it normally returns 'maybe or
 ;; 'found for) as actual types (and always return 'found for them).
@@ -4375,7 +5350,7 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-forward-<>-arglist (all-types)
   ;; The point is assumed to be at a "<".  Try to treat it as the open
-  ;; paren of an angle bracket arglist and move forward to the the
+  ;; paren of an angle bracket arglist and move forward to the
   ;; corresponding ">".  If successful, the point is left after the
   ;; ">" and t is returned, otherwise the point isn't moved and nil is
   ;; returned.  If ALL-TYPES is t then all encountered arguments in
@@ -7097,7 +8072,7 @@ comment at the start of cc-engine.el for more info."
   ;;
   ;; This function might do hidden buffer changes.
   (c-at-statement-start-p))
-(make-obsolete 'c-looking-at-bos 'c-at-statement-start-p)
+(make-obsolete 'c-looking-at-bos 'c-at-statement-start-p "22.1")
 
 (defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end)
   ;; Return non-nil if we're looking at the beginning of a block
@@ -7651,6 +8626,7 @@ comment at the start of cc-engine.el for more info."
           literal char-before-ip before-ws-ip char-after-ip macro-start
           in-macro-expr c-syntactic-context placeholder c-in-literal-cache
           step-type tmpsymbol keyword injava-inher special-brace-list tmp-pos
+          containing-<
           ;; The following record some positions for the containing
           ;; declaration block if we're directly within one:
           ;; `containing-decl-open' is the position of the open
@@ -8265,7 +9241,7 @@ comment at the start of cc-engine.el for more info."
                  (back-to-indentation)))
              ;; FIXME: Should use c-add-stmt-syntax, but it's not yet
              ;; template aware.
-             (c-add-syntax 'template-args-cont (point)))
+             (c-add-syntax 'template-args-cont (point) placeholder))
 
             ;; CASE 5D.4: perhaps a multiple inheritance line?
             ((and (c-major-mode-is 'c++-mode)
@@ -8477,10 +9453,11 @@ comment at the start of cc-engine.el for more info."
           ;; arglist that begins on the previous line.
           ((and c-recognize-<>-arglists
                 (eq (char-before) ?<)
+                (setq placeholder (1- (point)))
                 (not (and c-overloadable-operators-regexp
                           (c-after-special-operator-id lim))))
            (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
-           (c-add-syntax 'template-args-cont (c-point 'boi)))
+           (c-add-syntax 'template-args-cont (c-point 'boi) placeholder))
 
           ;; CASE 5Q: we are at a statement within a macro.
           (macro-start
@@ -8502,14 +9479,38 @@ comment at the start of cc-engine.el for more info."
 
         ;; (CASE 6 has been removed.)
 
+        ;; CASE 19: line is an expression, not a statement, and is directly
+        ;; contained by a template delimiter.  Most likely, we are in a
+        ;; template arglist within a statement.  This case is based on CASE
+        ;; 7.  At some point in the future, we may wish to create more
+        ;; syntactic symbols such as `template-intro',
+        ;; `template-cont-nonempty', etc., and distinguish between them as we
+        ;; do for `arglist-intro' etc. (2009-12-07).
+        ((and c-recognize-<>-arglists
+              (setq containing-< (c-up-list-backward indent-point containing-sexp))
+              (eq (char-after containing-<) ?\<))
+         (setq placeholder (c-point 'boi containing-<))
+         (goto-char containing-sexp)   ; Most nested Lbrace/Lparen (but not
+                                       ; '<') before indent-point.
+         (if (>= (point) placeholder)
+             (progn
+               (forward-char)
+               (skip-chars-forward " \t"))
+           (goto-char placeholder))
+         (c-add-stmt-syntax 'template-args-cont (list containing-<) t
+                            (c-most-enclosing-brace c-state-cache (point))
+                            paren-state))
+                            
+
         ;; CASE 7: line is an expression, not a statement.  Most
         ;; likely we are either in a function prototype or a function
-        ;; call argument list
+        ;; call argument list, or a template argument list.
         ((not (or (and c-special-brace-lists
                        (save-excursion
                          (goto-char containing-sexp)
                          (c-looking-at-special-brace-list)))
-                  (eq (char-after containing-sexp) ?{)))
+                  (eq (char-after containing-sexp) ?{)
+                  (eq (char-after containing-sexp) ?<)))
          (cond
 
           ;; CASE 7A: we are looking at the arglist closing paren.
@@ -8606,7 +9607,7 @@ comment at the start of cc-engine.el for more info."
                   (c-forward-syntactic-ws)
                   (point))
                 (c-point 'bonl)))
-           (goto-char containing-sexp)
+           (goto-char containing-sexp) ; paren opening the arglist
            (setq placeholder (c-point 'boi))
            (if (and (c-safe (backward-up-list 1) t)
                     (>= (point) placeholder))