From 027ed63c08e2f88fffb80e1b5b12197396da836b Mon Sep 17 00:00:00 2001 From: Chris Hanson Date: Tue, 29 Oct 1991 13:44:38 +0000 Subject: [PATCH] Fix numerous bugs in C indentation code. Upgrade C mode and C indentation to standard of Emacs 18.57. --- v7/src/edwin/c-mode.scm | 167 ++++++++----- v7/src/edwin/cinden.scm | 540 +++++++++++++++++++++++----------------- v7/src/edwin/edwin.pkg | 6 +- 3 files changed, 425 insertions(+), 288 deletions(-) diff --git a/v7/src/edwin/c-mode.scm b/v7/src/edwin/c-mode.scm index 4214585bc..0d1ecaba4 100644 --- a/v7/src/edwin/c-mode.scm +++ b/v7/src/edwin/c-mode.scm @@ -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))) - + (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 #\' "\"") - + (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) + (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)))) (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 () diff --git a/v7/src/edwin/cinden.scm b/v7/src/edwin/cinden.scm index 5b224b2bd..3d85d311d 100644 --- a/v7/src/edwin/cinden.scm +++ b/v7/src/edwin/cinden.scm @@ -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 ;;; @@ -48,167 +48,325 @@ (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?) + (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))) (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))))))) + (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)))))) - -(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))))))) + +(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*))))))) + +(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)))) + (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)) @@ -226,114 +384,38 @@ (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)) - -(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))))) - -(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 diff --git a/v7/src/edwin/edwin.pkg b/v7/src/edwin/edwin.pkg index c963389e8..ffc4a8596 100644 --- a/v7/src/edwin/edwin.pkg +++ b/v7/src/edwin/edwin.pkg @@ -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)) -- 2.25.1