unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* c mode still slow?
@ 2011-03-21 12:40 Dave Milter
  2011-03-21 13:37 ` Eli Zaretskii
  2011-03-21 19:41 ` Alan Mackenzie
  0 siblings, 2 replies; 4+ messages in thread
From: Dave Milter @ 2011-03-21 12:40 UTC (permalink / raw)
  To: Alan Mackenzie, emacs-devel

Hi, Alan and all.

Year or two ago I wrote email about emacs usage for C/C++ coding, how
it is painfully slow.

Any progress since then?

At now I have GNU Emacs 23.3.1 on Linux.

I open two files: one with defines, and another with functions, and
get such results:

font-lock-fontify-region                                   4
41.44931      10.3623275
font-lock-default-fontify-region                           4
41.44925      10.3623125
font-lock-fontify-keywords-region                          4
41.436062     10.3590155
font-lock-fontify-syntactically-region                     4
0.0126299999  0.0031574999
font-lock-extend-region-wholelines                         4
0.0003000000  7.500...e-05
font-lock-mode                                             5
8.8e-05       1.76e-05
font-lock-unfontify-region                                 4
6.3e-05       1.575e-05
font-lock-change-mode                                      2
5.7e-05       2.85e-05
font-lock-default-function                                 5
2.800...e-05  5.600...e-06
font-lock-default-unfontify-region                         4
1.399...e-05  3.499...e-06
font-lock-extend-region-multiline                          4
1.1e-05       2.75e-06
font-lock-set-defaults                                     4
9e-06         2.25e-06


font-lock-fontify-region                                   129
38.551784999  0.2988510465
font-lock-default-fontify-region                           129
38.549996     0.2988371782
font-lock-fontify-keywords-region                          129
38.367797999  0.2974247906
font-lock-fontify-syntactically-region                     129
0.174543      0.0013530465
font-lock-unfontify-region                                 129
0.0017679999  1.370...e-05
font-lock-default-unfontify-region                         129
0.0004499999  3.488...e-06
font-lock-set-defaults                                     129
0.0003079999  2.387...e-06
font-lock-extend-region-wholelines                         129
0.0002979999  2.310...e-06
font-lock-extend-region-multiline                          129
0.0002949999  2.286...e-06
font-lock-mode                                             1
1.9e-05       1.9e-05
font-lock-default-function                                 1
5e-06         5e-06

As you can see it take ages to show me content, and it still painfully
to work with such slow editor.

But of course without highlighting types and function names work is
also painful.

I wonder, may it is possible to process code into background, to allow
user work without any delay?



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c mode still slow?
  2011-03-21 12:40 c mode still slow? Dave Milter
@ 2011-03-21 13:37 ` Eli Zaretskii
  2011-03-21 19:41 ` Alan Mackenzie
  1 sibling, 0 replies; 4+ messages in thread
From: Eli Zaretskii @ 2011-03-21 13:37 UTC (permalink / raw)
  To: Dave Milter; +Cc: acm, emacs-devel

> Date: Mon, 21 Mar 2011 15:40:51 +0300
> From: Dave Milter <davemilter@gmail.com>
> Cc: 
> 
> I wonder, may it is possible to process code into background, to allow
> user work without any delay?

Is jit-lock-mode turned on in your sessions?  If not, turn it on and
try again.

If JIT Lock is still not fast enough, try customizing
jit-lock-stealth-time (I have it set to 16, FWIW), and if that still
doesn't give you results you want, customize jit-lock-defer-time to
something like 0.25.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c mode still slow?
  2011-03-21 12:40 c mode still slow? Dave Milter
  2011-03-21 13:37 ` Eli Zaretskii
@ 2011-03-21 19:41 ` Alan Mackenzie
  2011-03-22 22:25   ` Alan Mackenzie
  1 sibling, 1 reply; 4+ messages in thread
From: Alan Mackenzie @ 2011-03-21 19:41 UTC (permalink / raw)
  To: Dave Milter; +Cc: Eli Zaretskii, emacs-devel

Hi, Dave!

On Mon, Mar 21, 2011 at 03:40:51PM +0300, Dave Milter wrote:
> Hi, Alan and all.

> Year or two ago I wrote email about emacs usage for C/C++ coding, how
> it is painfully slow.

Yes, I remember it well!  I think your email was on 1st December 2008,
and your test file was composed of thousands of #defines without any
braces.  To fix that, I optimised an internal "brace cache" to cope
with this (reasonable) situation.  Unfortunately, there were doubts
about the absolute correctness of the change (which was large), so it
sadly didn't get included in Emacs 23.3.  It will be in Emacs 24.

> Any progress since then?

> At now I have GNU Emacs 23.3.1 on Linux.

> I open two files: one with defines, and another with functions, and
> get such results:

Give me a little time, and I will send you the patch again, in a form
which can be applied to Emacs 23.3.  This will hopefully fix (again) the
problem with the "#define" file.  If the file with the functions is
still sluggish, I'd like to hear from you again, with the file (if
possible).

Thanks for taking the trouble to report this bug again.  ;-(

> As you can see it take ages to show me content, and it still painfully
> to work with such slow editor.

> But of course without highlighting types and function names work is
> also painful.

> I wonder, may it is possible to process code into background, to allow
> user work without any delay?

Give me a day or two!

-- 
Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c mode still slow?
  2011-03-21 19:41 ` Alan Mackenzie
@ 2011-03-22 22:25   ` Alan Mackenzie
  0 siblings, 0 replies; 4+ messages in thread
From: Alan Mackenzie @ 2011-03-22 22:25 UTC (permalink / raw)
  To: Dave Milter; +Cc: emacs-devel

Hi, Dave!

On Mon, Mar 21, 2011 at 07:41:55PM +0000, Alan Mackenzie wrote:
> Hi, Dave!

> On Mon, Mar 21, 2011 at 03:40:51PM +0300, Dave Milter wrote:
> > Hi, Alan and all.

> > Year or two ago I wrote email about emacs usage for C/C++ coding, how
> > it is painfully slow.

> Yes, I remember it well!  I think your email was on 1st December 2008,
> and your test file was composed of thousands of #defines without any
> braces.  To fix that, I optimised an internal "brace cache" to cope
> with this (reasonable) situation.  Unfortunately, there were doubts
> about the absolute correctness of the change (which was large), so it
> sadly didn't get included in Emacs 23.3.  It will be in Emacs 24.

> Give me a little time, and I will send you the patch again, in a form
> which can be applied to Emacs 23.3.  This will hopefully fix (again) the
> problem with the "#define" file.  If the file with the functions is
> still sluggish, I'd like to hear from you again, with the file (if
> possible).

Here is the patch to cc-engine.el that you need.  Have fun!


*** cc-engine.el.orig	2011-02-13 20:09:53.000000000 +0000
--- cc-engine.el	2011-03-22 22:09:48.627885672 +0000
***************
*** 1947,1956 ****
  \f
  ;; A system for finding noteworthy parens before the point.
  
  (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.
  ;;
  ;; 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
--- 1947,1964 ----
  \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.  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
***************
*** 1959,1976 ****
  ;; 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.
  ;;
  ;; 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
--- 1967,1978 ----
  ;; most effective if `c-parse-state' is used on each line while moving
  ;; forward.
  
  (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, 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
***************
*** 1978,2290 ****
  ;; 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.
  
! (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.
    (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)
  	(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.
    ;;
    ;; 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:
    ;;
    ;;     {
    ;;     #define X {
    ;;     }
    ;;
    ;; This function might do hidden buffer changes.
  
!   (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)))
! 
!       ;; 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.
  (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 ((c-state-cache nil)
! 	  (c-state-cache-start 1)
! 	  (c-state-cache-good-pos 1))
        (setq res2 (c-real-parse-state)))
      (unless (equal res1 res2)
        ;; The cache can actually go further back due to the ad-hoc way
--- 1980,3087 ----
  ;; 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 or a cpp
+ ;; construct.  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.
+   ;;
+   ;; NOTE: This function manipulates `c-state-nonlit-pos-cache'.  This cache
+   ;; MAY NOT contain any positions within macros, since macros are frequently
+   ;; turned into comments by use of the `c-cpp-delimiter' category properties.
+   ;; We cannot rely on this mechanism whilst determining a cache pos since
+   ;; this function is also called from outwith `c-parse-state'.
+   (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.
+ 	  (goto-char pos)
+ 	  (when (and (c-beginning-of-macro) (/= (point) pos))
+ 	    (c-syntactic-end-of-macro)
+ 	    (or (eobp) (forward-char))
+ 	    (setq pos (point)))
+ 	  (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))
  
! 
! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
! ;; 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
! ;; 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)	; Pure elisp BOD.
  	(if (eq (char-after) ?\{)
  	    (setq cnt (1- cnt)))))
      (point)))
  
! (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))
! 
! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
! ;; Debugging routines to dump `c-state-cache' in a "replayable" form.
! ;; (defmacro c-sc-de (elt) 		; "c-state-cache-dump-element"
! ;;   `(format ,(concat "(setq " (symbol-name elt) " %s)    ") ,elt))
! ;; (defmacro c-sc-qde (elt)		; "c-state-cache-quote-dump-element"
! ;;   `(format ,(concat "(setq " (symbol-name elt) " '%s)    ") ,elt))
! ;; (defun c-state-dump ()
! ;;   ;; For debugging.
! ;;   ;(message
! ;;   (concat
! ;;    (c-sc-qde c-state-cache)
! ;;    (c-sc-de c-state-cache-good-pos)
! ;;    (c-sc-qde c-state-nonlit-pos-cache)
! ;;    (c-sc-de c-state-nonlit-pos-cache-limit)
! ;;    (c-sc-qde c-state-brace-pair-desert)
! ;;    (c-sc-de c-state-point-min)
! ;;    (c-sc-de c-state-point-min-lit-type)
! ;;    (c-sc-de c-state-point-min-lit-start)
! ;;    (c-sc-de c-state-min-scan-pos)
! ;;    (c-sc-de c-state-old-cpp-beg)
! ;;    (c-sc-de c-state-old-cpp-end)))
! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
! 
! (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.  (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)))))
  
! (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)))
!       )))
  
! ;; 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 ((here (point)) (res1 (c-real-parse-state)) res2)
      (let ((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))
        (setq res2 (c-real-parse-state)))
      (unless (equal res1 res2)
        ;; The cache can actually go further back due to the ad-hoc way
***************
*** 2296,2305 ****
  	(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: "
  			   "using cache: %s, from scratch: %s")
! 		   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))
--- 3093,3103 ----
  	(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 at %s: "
  			   "using cache: %s, from scratch: %s")
! 		   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))
***************
*** 2310,2315 ****
--- 3108,3114 ----
  (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.




> -- 
> Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-03-22 22:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-21 12:40 c mode still slow? Dave Milter
2011-03-21 13:37 ` Eli Zaretskii
2011-03-21 19:41 ` Alan Mackenzie
2011-03-22 22:25   ` Alan Mackenzie

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).