Fix numerous bugs in C indentation code. Upgrade C mode and C
authorChris Hanson <org/chris-hanson/cph>
Tue, 29 Oct 1991 13:44:38 +0000 (13:44 +0000)
committerChris Hanson <org/chris-hanson/cph>
Tue, 29 Oct 1991 13:44:38 +0000 (13:44 +0000)
indentation to standard of Emacs 18.57.

v7/src/edwin/c-mode.scm
v7/src/edwin/cinden.scm
v7/src/edwin/edwin.pkg

index 4214585bc94f8a39813334ac6efd84d742cd897a..0d1ecaba4655aeea58ac78c32e352ddb8c1de35b 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/c-mode.scm,v 1.47 1991/08/06 15:39:50 arthur Exp $
+;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/c-mode.scm,v 1.48 1991/10/29 13:44:38 cph Exp $
 ;;;
 ;;;    Copyright (c) 1986, 1989-91 Massachusetts Institute of Technology
 ;;;
@@ -58,11 +58,13 @@ Tab indents for C code.
 Comments are delimited with /* ... */.
 Paragraphs are separated by blank lines only.
 Delete converts tabs to spaces as it moves back.
-The characters { } ; : correct indentation when typed.
 
 Variables controlling indentation style:
+ c-tab-always-indent
+    True means TAB in C mode should always reindent the current line,
+    regardless of where in the line point is when the TAB command is used.
  c-auto-newline
-    Non-false means automatically newline before and after braces,
+    True means automatically newline before and after braces,
     and after colons and semicolons, inserted in C code.
  c-indent-level
     Indentation of C statements within surrounding block.
@@ -71,6 +73,9 @@ Variables controlling indentation style:
  c-continued-statement-offset
     Extra indentation given to a substatement, such as the
     then-clause of an if or body of a while.
+ c-continued-brace-offset
+    Extra indent for substatements that start with open-braces.
+    This is in addition to c-continued-statement-offset.
  c-brace-offset
     Extra indentation for line if it starts with an open brace.
  c-brace-imaginary-offset
@@ -79,36 +84,33 @@ Variables controlling indentation style:
  c-argdecl-indent
     Indentation level of declarations of C function arguments.
  c-label-offset
-    Extra indentation for line that is a label, or case or default."
+    Extra indentation for line that is a label, or case or default.
 
+Settings for K&R and BSD indentation styles are
+  c-indent-level                5    8
+  c-continued-statement-offset  5    8
+  c-brace-offset               -5   -8
+  c-argdecl-indent              0    8
+  c-label-offset               -5   -8"
   (local-set-variable! syntax-table c-mode:syntax-table)
   (local-set-variable! syntax-ignore-comments-backwards true)
-  (local-set-variable! paragraph-start "^$")
+  (local-set-variable! paragraph-start
+                      (string-append "^$\\|" (ref-variable page-delimiter)))
   (local-set-variable! paragraph-separate (ref-variable paragraph-start))
-  (local-set-variable! indent-line-procedure (ref-command c-indent-line))
+  (local-set-variable! paragraph-ignore-fill-prefix true)
+  (local-set-variable! indent-line-procedure (ref-command c-indent-command))
   (local-set-variable! require-final-newline true)
-  (local-set-variable! comment-locator-hook c-mode:comment-locate)
-  (local-set-variable! comment-indent-hook c-mode:comment-indent)
   (local-set-variable! comment-start "/* ")
   (local-set-variable! comment-end " */")
   (local-set-variable! comment-column 32)
+  (local-set-variable! comment-locator-hook c-mode:comment-locate)
+  (local-set-variable! comment-indent-hook c-mode:comment-indent)
   (event-distributor/invoke! (ref-variable c-mode-hook)))
-
+\f
 (define-variable c-mode-hook
   "An event distributor that is invoked when entering C mode."
   (make-event-distributor))
 
-(define-key 'c #\linefeed 'reindent-then-newline-and-indent)
-(define-key 'c #\) 'lisp-insert-paren)
-(define-key 'c #\{ 'electric-c-brace)
-(define-key 'c #\} 'electric-c-brace)
-(define-key 'c #\; 'electric-c-semi)
-(define-key 'c #\: 'electric-c-terminator)
-(define-key 'c #\c-m-h 'mark-c-procedure)
-(define-key 'c #\c-m-q 'c-indent-expression)
-(define-key 'c #\rubout 'backward-delete-char-untabify)
-(define-key 'c #\tab 'c-indent-line)
-
 (define c-mode:syntax-table (make-syntax-table))
 (modify-syntax-entry! c-mode:syntax-table #\\ "\\")
 (modify-syntax-entry! c-mode:syntax-table #\/ ". 14")
@@ -119,45 +121,66 @@ Variables controlling indentation style:
 (modify-syntax-entry! c-mode:syntax-table #\% ".")
 (modify-syntax-entry! c-mode:syntax-table #\< ".")
 (modify-syntax-entry! c-mode:syntax-table #\> ".")
+(modify-syntax-entry! c-mode:syntax-table #\& ".")
+(modify-syntax-entry! c-mode:syntax-table #\| ".")
 (modify-syntax-entry! c-mode:syntax-table #\' "\"")
-\f
+
 (define (c-mode:comment-locate start)
-  (and (re-search-forward "/\\*[ \t]*" start (line-end start 0))
+  (and (re-search-forward "/\\**" start (line-end start 0))
        (cons (re-match-start 0) (re-match-end 0))))
 
 (define (c-mode:comment-indent start)
   (if (re-match-forward "^/\\*" start (line-end start 0))
       0
-      (max (1+ (mark-column (horizontal-space-start start)))
-          (ref-variable comment-column))))
+      (max (+ (mark-column (horizontal-space-start start)) 1)
+          (ref-variable comment-column start))))
 
 (define-variable c-auto-newline
-  "Non-false means automatically newline before and after braces,
+  "True means automatically newline before and after braces,
 and after colons and semicolons, inserted in C code."
-  false)
+  false
+  boolean?)
 
+(define-variable c-tab-always-indent
+  "True means TAB in C mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used."
+  true
+  boolean?)
+
+(define-key 'c #\linefeed 'reindent-then-newline-and-indent)
+(define-key 'c #\) 'lisp-insert-paren)
+(define-key 'c #\{ 'electric-c-brace)
+(define-key 'c #\} 'electric-c-brace)
+(define-key 'c #\; 'electric-c-semi)
+(define-key 'c #\: 'electric-c-terminator)
+(define-key 'c #\c-m-h 'mark-c-procedure)
+(define-key 'c #\c-m-q 'indent-c-exp)
+(define-key 'c #\rubout 'backward-delete-char-untabify)
+(define-key 'c #\tab 'c-indent-command)
+\f
 (define-command electric-c-brace
   "Insert character and correct line's indentation."
   "P"
   (lambda (argument)
-    (let ((point (current-point)))
+    (let ((point (current-point))
+         (char (last-command-key)))
       (if (and (not argument)
               (line-end? point)
               (or (line-blank? point)
                   (and (ref-variable c-auto-newline)
                        (begin
-                         ((ref-command c-indent-line) false)
+                         ((ref-command c-indent-command) false)
                          (insert-newline)
                          true))))
          (begin
-           ((ref-command self-insert-command) false)
-           ((ref-command c-indent-line) false)
+           (insert-char char)
+           ((ref-command c-indent-command) false)
            (if (ref-variable c-auto-newline)
                (begin
                  (insert-newline)
-                 ((ref-command c-indent-line) false))))
+                 ((ref-command c-indent-command) false))))
          ((ref-command self-insert-command) false))
-      (if (eqv? #\} (current-command-key))
+      (if (eqv? #\} char)
          (mark-flash (backward-one-sexp (current-point)) 'RIGHT)))))
 
 (define-command electric-c-semi
@@ -172,24 +195,47 @@ and after colons and semicolons, inserted in C code."
   "Insert character and correct line's indentation."
   "P"
   (lambda (argument)
-    (let ((point (current-point)))
+    (let ((point (current-point))
+         (char (last-command-key)))
       (if (and (not argument)
               (line-end? point)
               (not (let ((mark (indentation-end point)))
                      (or (char-match-forward #\# mark)
-                         (let ((state (parse-partial-sexp mark point)))
+                         ;; Colon is special only after a label, or
+                         ;; case.  So quickly rule out most other
+                         ;; uses of colon and do no indentation for
+                         ;; them.
+                         (and (eqv? #\: char)
+                              (not (re-match-forward "case\\b"
+                                                     mark
+                                                     (line-end mark 0)
+                                                     false))
+                              (mark< (skip-chars-forward
+                                      " \t"
+                                      (forward-word mark 1))
+                                     point))
+                         (let ((state
+                                (parse-partial-sexp
+                                 (backward-definition-start point 1 'LIMIT)
+                                 point)))
                            (or (parse-state-in-string? state)
                                (parse-state-in-comment? state)
                                (parse-state-quoted? state)))))))
          (begin
-           ((ref-command self-insert-command) false)
-           ((ref-command c-indent-line) false)
+           (insert-char char)
+           ((ref-command c-indent-command) false)
            (if (and (ref-variable c-auto-newline)
                     (not (c-inside-parens? point)))
                (begin
                  (insert-newline)
-                 ((ref-command c-indent-line) false))))
+                 ((ref-command c-indent-command) false))))
          ((ref-command self-insert-command) argument)))))
+
+(define (c-inside-parens? mark)
+  (let ((container (backward-up-list mark 1 false)))
+    (and container
+        (mark>= container (backward-definition-start mark 1 'LIMIT))
+        (char-match-forward #\( container))))
 \f
 (define-command mark-c-procedure
   "Put mark at end of C procedure, point at beginning."
@@ -203,27 +249,36 @@ and after colons and semicolons, inserted in C code."
                           1
                           'LIMIT)))))
 
-(define-command c-indent-line
-  "Indent current line as C code.
-Argument means shift any additional lines of grouping
-rigidly with this line."
+(define-command c-indent-command
+  "Indent current line as C code, or in some cases insert a tab character.
+If c-tab-always-indent is true (the default), always indent current line.
+Otherwise, indent the current line only if point is at the left margin
+or in the line's indentation; otherwise insert a tab.
+
+A numeric argument, regardless of its value,
+means indent rigidly all the lines of the expression starting after point
+so that this line becomes properly indented.
+The relative indentation among the lines of the expression are preserved."
   "P"
   (lambda (#!optional argument)
-    (let ((argument (and (not (default-object? argument)) argument))
-         (start (line-start (current-point) 0)))
-      (let ((indentation (c-indent-line:indentation start)))
-       (let ((shift-amount (- indentation (mark-indentation start))))
-         (cond ((not (zero? shift-amount))
-                (change-indentation indentation start)
-                (if argument
-                    (indent-code-rigidly start
-                                         (forward-sexp start 1 'ERROR)
-                                         shift-amount
-                                         "#")))
-               ((within-indentation? (current-point))
-                (set-current-point! (indentation-end (current-point))))))))))
-
-(define-command c-indent-expression
+    (let ((point (current-point)))
+      (cond ((and (not (default-object? argument)) argument)
+            (let ((shift-amount (c-indent-line point))
+                  (start
+                   (if (ref-variable c-tab-always-indent)
+                       (line-start point 0)
+                       point)))
+              (indent-code-rigidly start
+                                   (forward-sexp start 1 'ERROR)
+                                   shift-amount
+                                   "#")))
+           ((or (ref-variable c-tab-always-indent)
+                (within-indentation? point))
+            (c-indent-line point))
+           (else
+            ((ref-command insert-tab)))))))
+
+(define-command indent-c-exp
   "Indent each line of the C grouping following point."
   ()
   (lambda ()
index 5b224b2bd48a3f24a3e2e459778727e2d4e3d0c2..3d85d311ddee24cd15822b787db17e8c75577989 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/cinden.scm,v 1.5 1991/04/21 00:49:09 cph Exp $
+;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/cinden.scm,v 1.6 1991/10/29 13:44:22 cph Exp $
 ;;;
 ;;;    Copyright (c) 1986, 1989-91 Massachusetts Institute of Technology
 ;;;
 \f
 (define-variable c-indent-level
   "Indentation of C statements with respect to containing block."
-  2)
-
-(define-variable c-brace-offset
-  "Extra indentation for braces, compared with other text in same context."
-  0)
+  2
+  exact-integer?)
 
 (define-variable c-brace-imaginary-offset
   "Imagined indentation of a C open brace that actually follows a statement."
-  0)
+  0
+  exact-integer?)
+
+(define-variable c-brace-offset
+  "Extra indentation for braces, compared with other text in same context."
+  0
+  exact-integer?)
 
 (define-variable c-argdecl-indent
   "Indentation level of declarations of C function arguments."
-  5)
+  5
+  exact-integer?)
 
 (define-variable c-label-offset
   "Offset of C label lines and case statements relative to usual indentation."
-  -2)
+  -2
+  exact-integer?)
 
 (define-variable c-continued-statement-offset
   "Extra indent for lines not starting new statements."
-  2)
+  2
+  exact-integer?)
 
+(define-variable c-continued-brace-offset
+  "Extra indent for substatements that start with open-braces.
+This is in addition to c-continued-statement-offset."
+  0
+  exact-integer?)
+\f
 (define (c-indent-line start)
-  (maybe-change-indentation (c-indent-line:indentation start) start))
-
-(define (c-indent-line:indentation start)
-  (with-variable-value! (ref-variable-object case-fold-search) false
-    (lambda ()
-      (let ((indentation (calculate-indentation start false)))
-       (cond ((not indentation) (mark-indentation start))
-             ((eq? indentation true)
-              ;; Inside a comment; indentation of line depends on
-              ;; whether or not it starts with a *.
-              (mark-column
-               (let ((end (whitespace-start start (group-start start))))
-                 (let ((iend (indentation-end end)))
-                   (let ((comstart (re-search-forward "/\\*[ \t]*" iend end)))
-                     (cond ((not comstart) iend)
-                           ((re-match-forward "[ \t]*\\*" start)
+  (let* ((start (line-start start 0))
+        (old-indentation (mark-indentation start))
+        (new-indentation
+         (let ((indentation (calculate-indentation start false)))
+           (cond ((not indentation)
+                  old-indentation)
+                 ((eq? indentation true)
+                  ;; Inside a comment.
+                  (mark-column
+                   (let* ((star?
+                           (char-match-forward #\* (indentation-end start)))
+                          (pend (whitespace-start start (group-start start)))
+                          (pstart (indentation-end pend))
+                          (comment-start
+                           (and (mark< pstart pend)
+                                (re-search-forward "/\\*[ \t]*" pstart pend
+                                                   false))))
+                     (cond ((not comment-start)
+                            pstart)
+                           (star?
                             (mark1+ (re-match-start 0)))
-                           (else comstart)))))))
-             ((char-match-forward #\# start) 0)
-             (else
-              (indent-line:adjust-indentation (horizontal-space-end start)
-                                              indentation)))))))
+                           (else
+                            comment-start)))))
+                 ((char-match-forward #\# start)
+                  0)
+                 (else
+                  (indent-line:adjust-indentation (horizontal-space-end start)
+                                                  indentation))))))
+    (if (not (= new-indentation old-indentation))
+       (change-indentation new-indentation start))
+    (- new-indentation old-indentation)))
 
 (define (indent-line:adjust-indentation start indentation)
-  (cond ((or (re-match-forward "case\\b" start)
+  (cond ((or (looking-at-keyword? "case" start)
             (and (re-match-forward "[A-Za-z]" start)
-                 (char-match-forward #\: (forward-one-sexp start))))
-        (max 1 (+ indentation (ref-variable c-label-offset))))
-       ((re-match-forward "else\\b" start)
+                 (char-match-forward #\: (forward-sexp start 1 'LIMIT))))
+        (max 1 (+ indentation (ref-variable c-label-offset start))))
+       ((looking-at-keyword? "else" start)
         (mark-indentation
-         (backward-to-start-of-if start
-                                  (backward-one-definition-start start))))
+         (backward-to-start-of-if
+          start
+          (backward-definition-start start 1 'LIMIT))))
        ((char-match-forward #\} start)
-        (- indentation (ref-variable c-indent-level)))
+        (- indentation (ref-variable c-indent-level start)))
        ((char-match-forward #\{ start)
-        (+ indentation (ref-variable c-brace-offset)))
+        (+ indentation (ref-variable c-brace-offset start)))
        (else indentation)))
 \f
 (define (calculate-indentation mark parse-start)
-  (let ((gstart (group-start mark))
-       (indent-point (line-start mark 0)))
-    (define (find-outer-container start)
-      (let ((state (parse-partial-sexp start indent-point 0)))
-       (if (mark= (parse-state-location state) indent-point)
-           state
-           (find-outer-container (parse-state-location state)))))
+  (let ((indent-point (line-start mark 0)))
     (let ((state
-          (find-outer-container (or parse-start
-                                    (backward-one-definition-start mark)
-                                    gstart))))
-      (if (or (parse-state-in-string? state)
-             (parse-state-in-comment? state))
-         ;; Return boolean if line should not be changed.
-         (not (not (parse-state-in-comment? state)))
-         (let ((container (parse-state-containing-sexp state)))
-           (cond ((not container)
-                  ;; Line is at top level.  Discriminate between
-                  ;; procedure definition and other cases.
-                  (if (re-match-forward "[ \t]*{" indent-point)
-                      0
-                      ;; May be data definition, or may be function
-                      ;; argument declaration.  Indent like the
-                      ;; previous top level line unless that ends
-                      ;; in a closeparen without semicolon, in
-                      ;; which case this line is the first argument
-                      ;; decl.
-                      (let ((mark
-                             (backward-to-noncomment indent-point
-                                                     (or parse-start
-                                                         gstart))))
-                        (if (char-match-backward #\) mark)
-                            (ref-variable c-argdecl-indent)
-                            (mark-indentation mark)))))
-                 ((char-match-forward #\{ container)
-                  (calculate-indentation:statement indent-point container))
-                 (else
-                  ;; Line is expression, not statement: indent to just
-                  ;; after the surrounding open.
-                  (mark-column (mark1+ container)))))))))
+          (let loop
+              ((start
+                (or parse-start (backward-definition-start mark 1 'LIMIT))))
+            (let ((state (parse-partial-sexp start indent-point 0)))
+              (if (mark= (parse-state-location state) indent-point)
+                  state
+                  (loop (parse-state-location state)))))))
+      (let ((container (parse-state-containing-sexp state)))
+       (cond ((parse-state-in-string? state)
+              false)
+             ((parse-state-in-comment? state)
+              true)
+             ((not container)
+              (calculate-indentation:top-level indent-point
+                                               (or parse-start
+                                                   (group-start mark))))
+             ((char-match-forward #\{ container)
+              (calculate-indentation:statement indent-point container))
+             (else
+              ;; Line is expression, not statement: indent to just
+              ;; after the surrounding open.
+              (mark-column (mark1+ container))))))))
 
+(define (calculate-indentation:top-level indent-point parse-start)
+  (let ((gend (group-end indent-point)))
+    ;; Discriminate between procedure definition and other cases.
+    (if (re-match-forward "[ \t]*{" indent-point gend false)
+       0
+       ;; May be data definition, or may be function argument
+       ;; declaration.  Indent like the previous top level line
+       ;; unless that ends in a closeparen without semicolon, in
+       ;; which case this line is the first argument decl.
+       (let* ((mark (backward-to-noncomment indent-point parse-start))
+              ;; Look at previous line that's at column zero to
+              ;; determine whether we are in top-level decls or
+              ;; function's arg decls.  Set basic-indent accordingly.
+              (basic-indent
+               (let ((m
+                      (and mark
+                           (re-search-backward "^[ \t\n\f#]"
+                                               mark
+                                               (group-start indent-point)
+                                               false))))
+                 (if (and m
+                          (re-match-forward "\\sw\\|\\s_" m gend false)
+                          (re-match-forward ".*(" m gend false)
+                          (let ((m
+                                 (forward-sexp (mark-1+ (re-match-end 0)) 1)))
+                            (and m
+                                 (mark< m indent-point)
+                                 (not (re-match-forward "[ \t\n]*[,;]"
+                                                        m gend false)))))
+                     (ref-variable c-argdecl-indent indent-point)
+                     0))))
+         (if (or (not mark) (memv (extract-left-char mark) '(#F #\) #\; #\})))
+             basic-indent
+             (+ basic-indent
+                (ref-variable c-continued-statement-offset indent-point)))))))
+\f
 (define (calculate-indentation:statement indent-point container)
-  (let ((mark (backward-to-noncomment indent-point container)))
-    (if (and mark
-            (re-match-forward "[^,;:{}]" (mark-1+ mark)))
+  (let ((mark
+        (let loop ((start indent-point))
+          (let ((m (backward-to-noncomment start container)))
+            ;; Back up over label lines, since they don't affect
+            ;; whether our line is a continuation.
+            (case (and m (mark> m container) (extract-left-char m))
+              ((#\:)
+               (if (let ((m (backward-to-noncomment (mark-1+ m) container)))
+                     (and m
+                          (mark> m container)
+                          (re-match-forward "'\\|\\sw\\|\\s_" (mark-1+ m))))
+                   (loop (line-start m 0))
+                   m))
+              ((#\,)
+               (loop
+                (line-start (backward-to-start-of-continued-exp m container)
+                            0)))
+              (else m))))))
+    (if (and mark (not (memv (extract-left-char mark) '(#F #\, #\; #\{ #\}))))
        ;; This line is continuation of preceding line's statement;
-       ;; indent C Continued Statement Offset more than the previous
+       ;; indent c-continued-statement-offset more than the previous
        ;; line of the statement.
-       (+ (ref-variable c-continued-statement-offset)
-          (mark-column (backward-to-start-of-continued-exp mark container)))
-       (let ((mark (skip-comments&labels (mark1+ container) indent-point)))
-         (if (not mark)
-             ;; If this is first statement after open brace, indent
-             ;; it relative to line brace is on.  For open brace in
-             ;; column zero, don't let statement start there too.  If
-             ;; C Indent Level is zero, use C Brace Offset + C
-             ;; Continued Statement Offset instead.  For open-braces
-             ;; not the first thing in a line, add in C Brace
-             ;; Imaginary Offset.
-             (+ (if (and (line-start? container)
-                         (zero? (ref-variable c-indent-level)))
-                    (+ (ref-variable c-brace-offset)
-                       (ref-variable c-continued-statement-offset))
-                    (ref-variable c-indent-level))
-                (+ (if (within-indentation? container)
+       (+ (ref-variable c-continued-statement-offset indent-point)
+          (mark-column (backward-to-start-of-continued-exp mark container))
+          (if (re-match-forward "[ \t]*{" indent-point)
+              (ref-variable c-continued-brace-offset indent-point)
+              0))
+       (or (skip-comments&labels (mark1+ container) indent-point)
+           ;; If no previous statement, indent it relative to line
+           ;; brace is on.  For open brace in column zero, don't let
+           ;; statement start there too.  If c-indent-level is zero,
+           ;; use c-brace-offset + c-continued-statement-offset
+           ;; instead.  For open-braces not the first thing in a
+           ;; line, add in c-brace-imaginary-offset.
+           (+ (if (and (line-start? container)
+                       (= 0 (ref-variable c-indent-level indent-point)))
+                  (+ (ref-variable c-brace-offset indent-point)
+                     (ref-variable c-continued-statement-offset indent-point))
+                  (ref-variable c-indent-level indent-point))
+              (let ((container (skip-chars-backward " \t" container)))
+                ;; If open brace is not the first non-white thing on
+                ;; the line, add the c-brace-imaginary-offset.
+                (+ (if (line-start? container)
                        0
-                       (ref-variable c-brace-imaginary-offset))
-                   (mark-indentation container)))
-             ;; Otherwise, indent under that first statement.
-             (mark-column mark))))))
-\f
-(define (skip-comments&labels start end)
-  (define (phi1 mark)
-    (cond ((mark= mark end) false)
-         ((char-match-forward #\# mark)
-          (phi2 (line-start mark 1)))
-         ((match-forward "/*" mark)
-          (phi2 (search-forward "*/" mark end)))
-         ((re-match-forward "case[ \t\n]\\|[a-zA-Z0-9_$]*:" mark)
-          (phi2 (char-search-forward #\: mark end)))
-         (else mark)))
+                       (ref-variable c-brace-imaginary-offset indent-point))
+                   (mark-indentation
+                    ;; If the open brace is preceded by a
+                    ;; parenthesized expression, move to the
+                    ;; beginning of that; possibly a different line.
+                    (if (eqv? #\) (extract-left-char container))
+                        (backward-sexp container 1 'LIMIT)
+                        container)))))))))
 
-  (define (phi2 mark)
-    (and mark
-        (phi1 (whitespace-end mark end))))
-
-  (phi1 (whitespace-end start end)))
+(define (skip-comments&labels start end)
+  (let ((gend (group-end start)))
+    (let loop ((mark start) (colon-line-end 0))
+      (let ((mark (whitespace-end mark gend)))
+       (cond ((mark>= mark end)
+              false)
+             ((char-match-forward #\# mark)
+              (loop (line-start mark 1 'LIMIT) colon-line-end))
+             ((match-forward "/*" mark)
+              (loop (or (search-forward "*/" mark gend) gend) colon-line-end))
+             ((re-match-forward "case[ \t\n].*:\\|[a-zA-Z0-9_$]*[ \t\n]*:"
+                                mark gend false)
+              (loop (re-match-end 0) (line-end mark 0)))
+             ((mark> colon-line-end mark)
+              (- (mark-indentation mark)
+                 (ref-variable c-label-offset mark)))
+             (else
+              (mark-column mark)))))))
+\f
+(define (c-indent-expression expression-start)
+  (let ((end
+        (mark-left-inserting-copy
+         (line-start (forward-sexp expression-start 1 'ERROR) 0))))
+    (let loop
+       ((start expression-start)
+        (state false)
+        (indent-stack (list false))
+        (contain-stack (list expression-start))
+        (last-depth 0))
+      (with-values (lambda () (c-indent-expression:parse-line start end state))
+       (lambda (start state)
+         (let* ((depth (parse-state-depth state))
+                (depth-delta (- depth last-depth))
+                (indent-stack (adjust-stack depth-delta indent-stack))
+                (contain-stack (adjust-stack depth-delta contain-stack))
+                (indent-line
+                 (lambda ()
+                   (if (not (line-blank? start))
+                       (c-indent-expression:per-line
+                        (skip-chars-forward " \t" start)
+                        expression-start
+                        indent-stack
+                        contain-stack)))))
+           (if (not (car contain-stack))
+               (set-car! contain-stack
+                         (or (parse-state-containing-sexp state)
+                             (backward-sexp start 1 'LIMIT))))
+           (if (mark= start end)
+               (begin
+                 (mark-temporary! end)
+                 (indent-line))
+               (begin
+                 (indent-line)
+                 (loop start state indent-stack contain-stack depth)))))))))
 
+(define (c-indent-expression:parse-line start end state)
+  (let loop ((start start) (state state))
+    (let ((start* (line-start start 1)))
+      (let ((state*
+            (parse-partial-sexp start start* false false state)))
+       (if (and state (parse-state-in-comment? state))
+           (c-indent-line start))
+       (cond ((mark= start* end)
+              (values start* state*))
+             ((parse-state-in-comment? state*)
+              (if (not (and state (parse-state-in-comment? state)))
+                  (if (re-search-forward "/\\*[ \t]*" start start* false)
+                      (c-mode:comment-indent (re-match-start 0))
+                      (error "Missing comment")))
+              (loop start* state*))
+             ((parse-state-in-string? state*)
+              (loop start* state*))
+             (else
+              (values start* state*)))))))
+\f
+(define (c-indent-expression:per-line start expression-start
+                                     indent-stack contain-stack)
+  (let ((indentation
+        (indent-line:adjust-indentation
+         start
+         (cond ((not (car indent-stack))
+                (let ((indentation (calculate-indentation start false)))
+                  (set-car! indent-stack indentation)
+                  indentation))
+               ((not (char-match-forward #\{ (car contain-stack)))
+                (car indent-stack))
+               (else
+                ;; Line is at statement level.  Is it a new
+                ;; statement?  Is it an else?  Find last non-comment
+                ;; character before this line.
+                (let ((mark (backward-to-noncomment start expression-start)))
+                  (cond ((not (memv (extract-left-char mark)
+                                    '(#F #\, #\; #\} #\: #\{)))
+                         (+ (ref-variable c-continued-statement-offset mark)
+                            (mark-column
+                             (backward-to-start-of-continued-exp
+                              mark
+                              (car contain-stack)))
+                            (if (char-match-forward #\{ start)
+                                (ref-variable c-continued-brace-offset mark)
+                                0)))
+                        ((looking-at-keyword? "else" start)
+                         (mark-indentation
+                          (backward-to-start-of-if mark expression-start)))
+                        (else
+                         (car indent-stack)))))))))
+    (if (not (char-match-forward #\# start))
+       (maybe-change-indentation indentation start))))
+\f
 (define (whitespace-start start end)
   (skip-chars-backward " \t\n" start end))
 
 (define (whitespace-end start end)
   (skip-chars-forward " \t\n" start end))
 
-(define (c-inside-parens? mark)
-  (let ((container (backward-up-one-list mark)))
-    (and container
-        (mark>= container (backward-one-definition-start mark))
-        (char-match-forward #\( container))))
+(define (looking-at-keyword? keyword start)
+  (let ((end (line-end start 0)))
+    (and (re-match-forward (string-append keyword "\\b") start end false)
+        (not (re-match-forward (string-append keyword "\\s_") start end
+                               false)))))
 
 (define (backward-to-noncomment start end)
   (let loop ((start start))
 (define (backward-to-start-of-continued-exp start end)
   (let ((mark
         (line-start (if (char-match-backward #\) start)
-                        (backward-one-sexp start)
+                        (backward-sexp start 1 'LIMIT)
                         start)
                     0)))
     (horizontal-space-end (if (mark<= mark end) (mark1+ end) mark))))
 
 (define (backward-to-start-of-if start end)
-  (define (phi2 mark if-level)
-    (define (phi1 if-level)
-      (if (zero? if-level)
-         mark
-         (phi2 (backward-sexp mark 1 'LIMIT) if-level)))
-    (cond ((re-match-forward "else\\b" mark)
-          (phi1 (1+ if-level)))
-         ((re-match-forward "if\\b" mark)
-          (phi1 (-1+ if-level)))
-         ((mark>= mark end)
-          (phi1 if-level))
-         (else end)))
-  (phi2 (backward-sexp start 1 'LIMIT) 1))
-\f
-(define (c-indent-expression expression-start)
-  (with-variable-value! (ref-variable-object case-fold-search) false
-    (lambda ()
-      (let ((end
-            (mark-left-inserting
-             (line-start (forward-sexp expression-start 1 'ERROR) 0))))
-       (define (loop start indent-stack contain-stack last-depth)
-         (next-line-start start false
-           (lambda (start state)
-             (let ((depth-delta (- (parse-state-depth state) last-depth)))
-               (let ((indent-stack (adjust-stack depth-delta indent-stack))
-                     (contain-stack (adjust-stack depth-delta contain-stack)))
-                 (if (not (car contain-stack))
-                     (set-car! contain-stack
-                               (or (parse-state-containing-sexp state)
-                                   (backward-one-sexp start))))
-                 (if (not (line-blank? start))
-                     (indent-line start indent-stack contain-stack))
-                 (if (not (mark= start end))
-                     (loop start indent-stack contain-stack
-                           (parse-state-depth state))))))))
-
-       (define (next-line-start start state receiver)
-         (let loop ((start start) (state state))
-           (let ((start* (line-start start 1)))
-             (let ((state*
-                    (parse-partial-sexp start start* false false state)))
-               (if (and state (parse-state-in-comment? state))
-                   (c-indent-line start))
-               (cond ((mark= start* end)
-                      (receiver start* state*))
-                     ((parse-state-in-comment? state*)
-                      (if (not (and state (parse-state-in-comment? state)))
-                          (if (re-search-forward "/\\*[ \t]*" start start*)
-                              (c-mode:comment-indent (re-match-start 0))
-                              (error "C-Indent-Expression: Missing comment")))
-                      (loop start* state*))
-                     ((parse-state-in-string? state*)
-                      (loop start* state*))
-                     (else
-                      (receiver start* state*)))))))
-
-       (define (indent-line start indent-stack contain-stack)
-         (let ((indentation
-                (indent-line:adjust-indentation
-                 start
-                 (if (car indent-stack)
-                     (if (char-match-forward #\{ (car contain-stack))
-                         ;; Line is at statement level.  Is it a new
-                         ;; statement?  Is it an else?  Find last
-                         ;; non-comment character before this line.
-                         (let ((mark
-                                (backward-to-noncomment
-                                 start expression-start)))
-                           (cond ((not (memv (extract-left-char mark)
-                                             '(#F #\. #\; #\} #\:)))
-                                  (+ (ref-variable
-                                      c-continued-statement-offset)
-                                     (mark-column
-                                      (backward-to-start-of-continued-exp
-                                       mark (car contain-stack)))))
-                                 ((re-match-forward "else\\b" start)
-                                  (mark-indentation
-                                   (backward-to-start-of-if
-                                    mark
-                                    expression-start)))
-                                 (else (car indent-stack))))
-                         (car indent-stack))
-                     (let ((indentation (calculate-indentation start false)))
-                       (set-car! indent-stack indentation)
-                       indentation)))))
-           (if (not (or (= indentation (mark-indentation start))
-                        (re-match-forward "[ \t]*#" start)))
-               (change-indentation indentation start))))
-
-       (loop expression-start (list false) (list expression-start) 0)))))
-\f
-(define (adjust-stack depth-delta indent-stack)
-  (cond ((zero? depth-delta) indent-stack)
-       ((positive? depth-delta) (up-stack depth-delta indent-stack))
-       (else (down-stack depth-delta indent-stack))))
-
-(define (down-stack n stack)
-  (if (= -1 n)
-      (cdr stack)
-      (down-stack (1+ n) (cdr stack))))
+  (let loop ((mark start) (if-level 1))
+    (let ((mark (backward-sexp mark 1 'LIMIT)))
+      (let ((adjust-level
+            (lambda (if-level)
+              (if (= if-level 0)
+                  mark
+                  (loop mark if-level)))))
+       (cond ((looking-at-keyword? "else" mark)
+              (adjust-level (+ if-level 1)))
+             ((looking-at-keyword? "if" mark)
+              (adjust-level (- if-level 1)))
+             ((mark>= mark end)
+              (adjust-level if-level))
+             (else
+              end))))))
 
-(define (up-stack n stack)
-  (if (= 1 n)
-      (cons false stack)
-      (up-stack (-1+ n) (cons false stack))))
\ No newline at end of file
+(define (adjust-stack depth-delta stack)
+  (cond ((= depth-delta 0)
+        stack)
+       ((> depth-delta 0)
+        (let loop ((depth-delta depth-delta) (stack stack))
+          (if (= 1 depth-delta)
+              (cons false stack)
+              (loop (- depth-delta 1) (cons false stack)))))
+       (else
+        (let loop ((depth-delta depth-delta) (stack stack))
+          (if (= -1 depth-delta)
+              (cdr stack)
+              (loop (+ depth-delta 1) (cdr stack)))))))
\ No newline at end of file
index c963389e83b5407332c339d47e90267cce03701b..ffc4a8596b2c9c9040c1fd04a84d8ef9b39f8b26 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/edwin.pkg,v 1.66 1991/10/26 21:54:48 cph Exp $
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/edwin.pkg,v 1.67 1991/10/29 13:44:08 cph Exp $
 
 Copyright (c) 1989-91 Massachusetts Institute of Technology
 
@@ -659,11 +659,11 @@ MIT in each case. |#
   (parent (edwin))
   (export (edwin)
          c-indent-expression
-         c-indent-line:indentation
-         c-inside-parens?
+         c-indent-line
          edwin-variable$c-argdecl-indent
          edwin-variable$c-brace-imaginary-offset
          edwin-variable$c-brace-offset
+         edwin-variable$c-continued-brace-offset
          edwin-variable$c-continued-statement-offset
          edwin-variable$c-indent-level
          edwin-variable$c-label-offset))