]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/fortran.el
(hide-ifdef-use-define-alist): Pass a list of
[gnu-emacs] / lisp / progmodes / fortran.el
index e158304b4160ccdb3a64e86259f2ccbce6604a81..371cc610912a877e7c8ec536bd53d9e59a45b7d3 100644 (file)
@@ -1,7 +1,7 @@
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
-;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 2001
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+;;               2003, 2004, 2005  Free Software Foundation, Inc.
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
 ;; Maintainer: Glenn Morris <gmorris@ast.cam.ac.uk>
@@ -21,8 +21,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -54,6 +54,7 @@
 ;; * Support any other extensions to f77 grokked by GNU Fortran I've missed.
 
 (eval-when-compile                     ; silence compiler
+  (defvar dabbrev-case-fold-search)
   (defvar imenu-case-fold-search)
   (defvar imenu-syntax-alist))
 
@@ -94,7 +95,7 @@ with a character in column 6."
   :group 'fortran-indent)
 
 (defcustom fortran-if-indent 3
-  "*Extra indentation applied to IF blocks."
+  "*Extra indentation applied to IF, SELECT CASE and WHERE blocks."
   :type  'integer
   :group 'fortran-indent)
 
@@ -146,7 +147,7 @@ You might want to change this to \"*\", for instance."
   "*Regexp to match a directive line.
 The matching text will be fontified with `font-lock-keyword-face'.
 The matching line will be given zero indentation."
-  :version "21.4"
+  :version "22.1"
   :type    'regexp
   :group   'fortran-indent)
 
@@ -236,10 +237,25 @@ See the variable `fortran-column-ruler-fixed' for fixed format mode."
 
 (defcustom fortran-break-before-delimiters t
   "*Non-nil causes filling to break lines before delimiters.
-Delimiters are whitespace, commas, quotes, and operators."
+Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
   :type  'boolean
   :group 'fortran)
 
+(defconst fortran-break-delimiters-re "[-+*/><=, \t]"
+  "Regexp matching delimiter characters at which lines may be broken.
+There are certain tokens comprised entirely of characters
+matching this regexp that should not be split, and these are
+specified by the constant `fortran-no-break-re'.")
+
+;; The ">=", etc F77 extensions are supported by g77.
+(defconst fortran-no-break-re
+  (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren)
+  "Regexp specifying where not to break lines when filling.
+This regexp matches certain tokens comprised entirely of
+characters matching the regexp `fortran-break-delimiters-re' that should
+not be split by filling.  Each element is assumed to be two
+characters long.")
+
 (defcustom fortran-mode-hook nil
   "Hook run when entering Fortran mode."
   :type  'hook
@@ -305,7 +321,8 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
                             "while" "inquire" "stop" "return"
                             "include" "open" "close" "read"
                             "write" "format" "print" "select" "case"
-                            "cycle" "exit" "rewind" "backspace")
+                            "cycle" "exit" "rewind" "backspace"
+                            "where" "elsewhere")
                           'paren) "\\>")
            ;; Builtin operators.
            (concat "\\." (regexp-opt
@@ -354,6 +371,29 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
                 fortran-font-lock-keywords-2)))
   "Gaudy level highlighting for Fortran mode.")
 
+(defvar fortran-font-lock-keywords-4
+  (append fortran-font-lock-keywords-3
+          (list (list
+                 (concat "\\<"
+                         (regexp-opt
+                          '("int" "ifix" "idint" "real" "float" "sngl"
+                            "dble" "cmplx" "ichar" "char" "aint" "dint"
+                            "anint" "dnint" "nint" "idnint" "iabs" "abs"
+                            "dabs" "cabs" "mod" "amod" "dmod" "isign"
+                            "sign" "dsign" "idim" "dim" "ddim" "dprod"
+                            "max" "max0" "amax1" "dmax1" "amax0" "max1"
+                            "min0" "amin1" "dmin1" "amin0" "min1" "len"
+                            "index" "lge" "lgt" "lle" "llt" "aimag"
+                            "conjg" "sqrt" "dsqrt" "csqrt" "exp" "dexp"
+                            "cexp" "log" "alog" "dlog" "clog" "log10"
+                            "alog10" "dlog10" "sin" "dsin" "csin" "cos"
+                            "dcos" "ccos" "tan" "dtan" "asin" "dasin"
+                            "acos" "dacos" "atan" "datan" "atan2" "datan2"
+                            "sinh" "dsinh" "cosh" "dcosh" "tanh" "dtanh")
+                          'paren) "[ \t]*(") '(1 font-lock-builtin-face))))
+  "Maximum highlighting for Fortran mode.
+Consists of level 3 plus all other intrinsics not already highlighted.")
+
 ;; Comments are real pain in Fortran because there is no way to
 ;; represent the standard comment syntax in an Emacs syntax table.
 ;; (We can do so for F90-style).  Therefore an unmatched quote in a
@@ -392,6 +432,64 @@ These get fixed-format comments fontified.")
    '(nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1))
   "Value for `imenu-generic-expression' in Fortran mode.")
 
+\f
+;; Hideshow support.
+(defconst fortran-blocks-re
+  (concat "block[ \t]*data\\|select[ \t]*case\\|"
+          (regexp-opt '("do" "if" "interface" "function" "map" "program"
+                        "structure" "subroutine" "union" "where")))
+  "Regexp potentially indicating the start or end of a Fortran \"block\".
+Omits naked END statements, and DO-loops closed by anything other
+than ENDDO.")
+
+(defconst fortran-end-block-re
+  ;; Do-loops terminated by things other than ENDDO cannot be handled
+  ;; with a regexp. This omission does not seem to matter to hideshow...
+  (concat "^[ \t0-9]*\\<end[ \t]*\\("
+          fortran-blocks-re
+          ;; Naked END statement.
+          "\\|!\\|$\\)")
+  "Regexp matching the end of a Fortran \"block\", from the line start.
+Note that only ENDDO is handled for the end of a DO-loop.  Used
+in the Fortran entry in `hs-special-modes-alist'.")
+
+(defconst fortran-start-block-re
+  (concat
+   "^[ \t0-9]*\\("                      ; statement number
+   ;; Structure label for DO, IF, SELECT, WHERE.
+   "\\(\\(\\sw+[ \t]*:[ \t]*\\)?"
+   ;; IF blocks are a nuisance:
+   ;; IF ( ... ) foo   is not a block, but a single statement.
+   ;; IF ( ... ) THEN  can be split over multiple lines.
+   ;; [So can, eg, a DO WHILE (... ), but that is less common, I hope.]
+   ;; The regexp below allows for it to be split over at most 2 lines.
+   ;; That leads to the problem of not matching two consecutive IF
+   ;; statements as one, eg:
+   ;; IF ( ... ) foo
+   ;; IF ( ... ) THEN
+   ;; It simply is not possible to do this in a 100% correct fashion
+   ;; using a regexp - see the functions fortran-end-if,
+   ;; fortran-beginning-if for the hoops we have to go through.
+   ;; An alternative is to match on THEN at a line end, eg:
+   ;;   ".*)[ \t]*then[ \t]*\\($\\|!\\)"
+   ;; This would also match ELSE branches, though. This does not seem
+   ;; right to me, because then one has neighbouring blocks that are
+   ;; not nested in each other.
+   "\\(if[ \t]*(\\(.*\\|"
+   ".*\n\\([^if]*\\([^i].\\|.[^f]\\|.\\>\\)\\)\\)\\<then\\|"
+   "do\\|select[ \t]*case\\|where\\)\\)\\|"
+   (regexp-opt '("interface" "function" "map" "program"
+                 "structure" "subroutine" "union"))
+   "\\|block[ \t]*data\\)[ \t]*")
+  "Regexp matching the start of a Fortran \"block\", from the line start.
+A simple regexp cannot do this in fully correct fashion, so this
+tries to strike a compromise between complexity and flexibility.
+Used in the Fortran entry in `hs-special-modes-alist'.")
+
+(add-to-list 'hs-special-modes-alist
+            `(fortran-mode ,fortran-start-block-re ,fortran-end-block-re
+                            "^[cC*!]" fortran-end-of-block nil))
+
 \f
 (defvar fortran-mode-syntax-table
   (let ((table (make-syntax-table)))
@@ -406,7 +504,8 @@ These get fixed-format comments fontified.")
     (modify-syntax-entry ?/  "."  table)
     (modify-syntax-entry ?\' "\"" table)
     (modify-syntax-entry ?\" "\"" table)
-    ;; Consistent with GNU Fortran -- see the manual.
+    ;; Consistent with GNU Fortran's default -- see the manual.
+    ;; The F77 standard imposes no rule on this issue.
     (modify-syntax-entry ?\\ "\\" table)
     ;; This might be better as punctuation, as for C, but this way you
     ;; can treat floating-point numbers as symbols.
@@ -418,12 +517,20 @@ These get fixed-format comments fontified.")
     table)
   "Syntax table used in Fortran mode.")
 
+(defvar fortran-gud-syntax-table
+  (let ((st (make-syntax-table fortran-mode-syntax-table)))
+    (modify-syntax-entry ?\n "." st)
+    st)
+  "Syntax table used to parse Fortran expressions for printing in GUD.")
+
 (defvar fortran-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map ";"        'fortran-abbrev-start)
     (define-key map "\C-c;"    'fortran-comment-region)
     (define-key map "\M-;"     'fortran-indent-comment)
     (define-key map "\M-\n"    'fortran-split-line)
+    (define-key map "\M-\C-n"  'fortran-end-of-block)
+    (define-key map "\M-\C-p"  'fortran-beginning-of-block)
     (define-key map "\M-\C-q"  'fortran-indent-subprogram)
     (define-key map "\C-c\C-w" 'fortran-window-create-momentarily)
     (define-key map "\C-c\C-r" 'fortran-column-ruler)
@@ -584,7 +691,7 @@ Key definitions:
 
 Variables controlling indentation style and extra features:
 
-`comment-start'
+`fortran-comment-line-start'
   To use comments starting with `!', set this to the string \"!\".
 `fortran-do-indent'
   Extra indentation within DO blocks (default 3).
@@ -652,7 +759,7 @@ with no args, if that value is non-nil."
          (let (fortran-blink-matching-if ; avoid blinking delay
                indent-region-function)
            (indent-region start end nil))))
-  (set (make-local-variable 'require-final-newline) t)
+  (set (make-local-variable 'require-final-newline) mode-require-final-newline)
   ;; The syntax tables don't understand the column-0 comment-markers.
   (set (make-local-variable 'comment-use-syntax) nil)
   (set (make-local-variable 'comment-padding) "$$$")
@@ -674,7 +781,8 @@ with no args, if that value is non-nil."
        '((fortran-font-lock-keywords
           fortran-font-lock-keywords-1
           fortran-font-lock-keywords-2
-          fortran-font-lock-keywords-3)
+          fortran-font-lock-keywords-3
+          fortran-font-lock-keywords-4)
          nil t ((?/ . "$/") ("_$" . "w"))
          fortran-beginning-of-subprogram))
   (set (make-local-variable 'font-lock-syntactic-keywords)
@@ -690,9 +798,15 @@ with no args, if that value is non-nil."
   (set (make-local-variable 'add-log-current-defun-function)
        #'fortran-current-defun)
   (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
-  (run-hooks 'fortran-mode-hook))
+  (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
+  (run-mode-hooks 'fortran-mode-hook))
 
 \f
+(defun fortran-gud-find-expr ()
+  ;; Consider \n as punctuation (end of expression).
+  (with-syntax-table fortran-gud-syntax-table
+    (gud-find-c-expr)))
+
 (defsubst fortran-comment-indent ()
   "Return the indentation appropriate for the current comment line.
 This is 0 for a line matching `fortran-comment-line-start-skip', else
@@ -700,8 +814,7 @@ the value of `comment-column' (leaving at least one space after code)."
   (if (looking-at fortran-comment-line-start-skip) 0
     (save-excursion
       (skip-chars-backward " \t")
-      (max (1+ (current-column))
-          comment-column))))
+      (max (1+ (current-column)) comment-column))))
 
 (defun fortran-indent-comment ()
   "Align or create comment on current line.
@@ -754,14 +867,14 @@ With non-nil ARG, uncomments the region."
     (goto-char beg-region)
     (beginning-of-line)
     (if arg
-        (let ((com (regexp-quote fortran-comment-region))) ;uncomment region
+        (let ((com (regexp-quote fortran-comment-region))) ; uncomment
           (if (looking-at com)
               (delete-region (point) (match-end 0)))
           (while (and (zerop (forward-line 1))
                       (< (point) end-region-mark))
             (if (looking-at com)
                 (delete-region (point) (match-end 0)))))
-      (insert fortran-comment-region) ;comment the region
+      (insert fortran-comment-region)   ; comment
       (while (and (zerop (forward-line 1))
                   (< (point) end-region-mark))
         (insert fortran-comment-region)))
@@ -774,13 +887,17 @@ With non-nil ARG, uncomments the region."
   "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
 Any other key combination is executed normally."
   (interactive "*")
-  (let (c)
-    (insert last-command-char)
-    (if (and abbrev-mode
-             (or (eq (setq c (read-event)) ??) ;insert char if not equal to `?'
-                 (eq c help-char)))
+  (insert last-command-char)
+  (let (char event)
+    (if (fboundp 'next-command-event) ; XEmacs
+        (setq event (next-command-event)
+              char (event-to-character event))
+      (setq event (read-event)
+            char event))
+    ;; Insert char if not equal to `?', or if abbrev-mode is off.
+    (if (and abbrev-mode (or (eq char ??) (eq char help-char)))
        (fortran-abbrev-help)
-      (setq unread-command-events (list c)))))
+      (setq unread-command-events (list event)))))
 
 (defun fortran-abbrev-help ()
   "List the currently defined abbrevs in Fortran mode."
@@ -802,9 +919,9 @@ Any other key combination is executed normally."
 
 (defun fortran-column-ruler ()
   "Insert a column ruler momentarily above current line, till next keystroke.
-The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed
-format mode, and `fortran-column-ruler-tab' when in TAB format mode.
-The key typed is executed unless it is SPC."
+The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed
+format mode, and `fortran-column-ruler-tab' in TAB format mode.
+The next key typed is executed unless it is SPC."
   (interactive)
   (momentary-string-display
    (if indent-tabs-mode
@@ -865,8 +982,8 @@ See also `fortran-window-create'."
       (insert ?\n (match-string 0))
     (if indent-tabs-mode
        (insert ?\n ?\t (fortran-numerical-continuation-char))
-      (insert "\n " fortran-continuation-string))) ; Space after \n important
-  (fortran-indent-line))               ; when the cont string is C, c or *.
+      (insert "\n " fortran-continuation-string))) ; space after \n important
+  (fortran-indent-line))               ; when cont string is C, c or *
 
 (defun fortran-remove-continuation ()
   "Delete any Fortran continuation characters at point.
@@ -921,7 +1038,7 @@ Auto-indent does not happen if a numeric ARG is used."
                        fortran-minimum-statement-indent-tab
                      fortran-minimum-statement-indent-fixed) (current-column))
                  ;; In col 8 with a single tab to the left.
-                (eq ?\t (char-after (line-beginning-position))) 
+                (eq ?\t (char-after (line-beginning-position)))
                 (not (or (eq last-command 'fortran-indent-line)
                          (eq last-command
                              'fortran-indent-new-line))))
@@ -936,7 +1053,6 @@ Auto-indent does not happen if a numeric ARG is used."
       (fortran-indent-line))))
 
 \f
-
 (defun fortran-check-end-prog-re ()
   "Check a preliminary match against `fortran-end-prog-re'."
   ;; Having got a possible match for the subprogram end, we need a
@@ -1029,6 +1145,84 @@ Directive lines are treated as comments."
     (if (not not-last-statement)
        'last-statement)))
 
+(defun fortran-looking-at-if-then ()
+  "Return non-nil if at the start of a line with an IF ... THEN statement."
+  ;; cf f90-looking-at-if-then.
+  (let ((p (point))
+        (i (fortran-beginning-if)))
+    (if i
+        (save-excursion
+          (goto-char i)
+          (beginning-of-line)
+          (= (point) p)))))
+
+;; Used in hs-special-modes-alist.
+(defun fortran-end-of-block (&optional num)
+  "Move point forward to the end of the current code block.
+With optional argument NUM, go forward that many balanced blocks.
+If NUM is negative, go backward to the start of a block.  Does
+not check for consistency of block types.  Interactively, pushes
+mark before moving point."
+  (interactive "p")
+  (if (interactive-p) (push-mark (point) t))
+  (and num (< num 0) (fortran-beginning-of-block (- num)))
+  (let ((case-fold-search t)
+        (count (or num 1)))
+    (end-of-line)
+    (while (and (> count 0)
+                (re-search-forward
+                 (concat "\\(" fortran-blocks-re
+                         (if fortran-check-all-num-for-matching-do
+                             "\\|^[ \t]*[0-9]+" "")
+                         "\\|continue\\|end\\)\\>")
+                 nil 'move))
+      (beginning-of-line)
+      (if (if (looking-at (concat "^[0-9 \t]*" fortran-if-start-re))
+              (fortran-looking-at-if-then)
+            (looking-at fortran-start-block-re))
+          (setq count (1+ count))
+        (if (or (looking-at fortran-end-block-re)
+                (and (or (looking-at "^[0-9 \t]*continue")
+                         (and fortran-check-all-num-for-matching-do
+                              (looking-at "[ \t]*[0-9]+")))
+                     (fortran-check-for-matching-do)))
+            (setq count (1- count))))
+      (end-of-line))
+    (if (> count 0) (error "Missing block end"))))
+
+(defun fortran-beginning-of-block (&optional num)
+  "Move point backwards to the start of the current code block.
+With optional argument NUM, go backward that many balanced
+blocks.  If NUM is negative, go forward to the end of a block.
+Does not check for consistency of block types.  Interactively,
+pushes mark before moving point."
+  (interactive "p")
+  (if (interactive-p) (push-mark (point) t))
+  (and num (< num 0) (fortran-end-of-block (- num)))
+  (let ((case-fold-search t)
+        (count (or num 1)))
+    (beginning-of-line)
+    (while (and (> count 0)
+                (re-search-backward
+                 (concat "\\(" fortran-blocks-re
+                         (if fortran-check-all-num-for-matching-do
+                             "\\|^[ \t]*[0-9]+" "")
+                         "\\|continue\\|end\\)\\>")
+                 nil 'move))
+      (beginning-of-line)
+      (if (if (looking-at (concat "^[0-9 \t]*" fortran-if-start-re))
+              (fortran-looking-at-if-then)
+            (looking-at fortran-start-block-re))
+          (setq count (1- count))
+        (if (or (looking-at fortran-end-block-re)
+                (and (or (looking-at "^[0-9 \t]*continue")
+                         (and fortran-check-all-num-for-matching-do
+                              (looking-at "[ \t]*[0-9]+")))
+                     (fortran-check-for-matching-do)))
+            (setq count (1+ count)))))
+    ;; Includes an un-named main program block.
+    (if (> count 0) (error "Missing block start"))))
+
 \f
 (defun fortran-blink-match (regex keyword find-begin)
   "From a line matching REGEX, blink matching KEYWORD statement line.
@@ -1093,7 +1287,7 @@ Return point or nil."
        (let ((count 1))
          (while (and (not (zerop count))
                      (not (eq (fortran-next-statement) 'last-statement))
-                     ;; Keep local to subprogram
+                     ;; Keep local to subprogram.
                      (not (and (looking-at fortran-end-prog-re)
                                (fortran-check-end-prog-re))))
            (skip-chars-forward " \t0-9")
@@ -1122,7 +1316,7 @@ Return point or nil.  Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)."
        (let ((count 1))
          (while (and (not (zerop count))
                      (not (eq (fortran-previous-statement) 'first-statement))
-                     ;; Keep local to subprogram
+                     ;; Keep local to subprogram.
                      (not (and (looking-at fortran-end-prog-re)
                                (fortran-check-end-prog-re))))
            (skip-chars-forward " \t0-9")
@@ -1173,7 +1367,7 @@ Return point or nil."
                   (save-excursion
                     (if (or
                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; Multi-line if-then.
+                         (let (then-test) ; multi-line if-then
                            (while
                                (and
                                 (zerop (forward-line 1))
@@ -1232,7 +1426,7 @@ Return point or nil."
                   (save-excursion
                     (if (or
                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; Multi-line if-then.
+                         (let (then-test) ; multi-line if-then
                            (while
                                (and
                                 (zerop (forward-line 1))
@@ -1327,9 +1521,9 @@ Return point or nil."
         (skip-chars-forward " \t0-9")
         (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(")
                (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
-                       (let (then-test)        ;multi-line if-then
+                       (let (then-test)        ; multi-line if-then
                          (while (and (zerop (forward-line 1))
-                                     ;;search forward for then
+                                     ;; Search forward for then.
                                      (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
                                      (not (setq then-test
                                                 (looking-at
@@ -1357,7 +1551,7 @@ Return point or nil."
                (setq icol (+ icol fortran-structure-indent)))
               ((and (looking-at fortran-end-prog-re1)
                     (fortran-check-end-prog-re))
-               ;; Previous END resets indent to minimum
+               ;; Previous END resets indent to minimum.
                (setq icol fortran-minimum-statement-indent)))))
     (save-excursion
       (beginning-of-line)
@@ -1470,8 +1664,8 @@ notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
                       (insert ?\t (fortran-numerical-continuation-char) 1))
              (forward-char 6))
          (delete-horizontal-space)
-         ;; Put line number in columns 0-4
-         ;; or put continuation character in column 5.
+         ;; Put line number in columns 0-4, or
+          ;; continuation character in column 5.
          (cond ((eobp))
                ((looking-at (regexp-quote fortran-continuation-string))
                 (if indent-tabs-mode
@@ -1521,7 +1715,7 @@ Otherwise return nil."
       (beginning-of-line)
       (when (looking-at "[ \t]*[0-9]+")
         (skip-chars-forward " \t")
-        (skip-chars-forward "0")       ;skip past leading zeros
+        (skip-chars-forward "0")       ; skip past leading zeros
         (setq charnum
               (buffer-substring (point) (progn
                                           (skip-chars-forward "0-9")
@@ -1573,18 +1767,17 @@ If ALL is nil, only match comments that start in column > 0."
      ((save-excursion                  ; comment lines too
        (beginning-of-line)
        (looking-at fortran-comment-line-start-skip)) nil)
-     (t (let (;; ok, serious now. Init some local vars:
-             (parse-state '(0 nil nil nil nil nil 0))
+     (t (let ((parse-state '(0 nil nil nil nil nil 0))
              (quoted-comment-start (if comment-start
                                        (regexp-quote comment-start)))
              (not-done t)
              parse-limit end-of-line)
-         ;; move to start of current statement
+         ;; Move to start of current statement.
          (fortran-next-statement)
          (fortran-previous-statement)
-         ;; now parse up to WHERE
+         ;; Now parse up to WHERE.
          (while not-done
-           (if (or ;; skip to next line if:
+           (if (or ;; Skip to next line if:
                 ;; - comment line?
                 (looking-at fortran-comment-line-start-skip)
                 ;; - at end of line?
@@ -1597,29 +1790,29 @@ If ALL is nil, only match comments that start in column > 0."
                (if (> (forward-line) 0)
                    (setq not-done nil))
              ;; else:
-             ;; if we are at beginning of code line, skip any
+             ;; If we are at beginning of code line, skip any
              ;; whitespace, labels and tab continuation markers.
              (if (bolp) (skip-chars-forward " \t0-9"))
-             ;; if we are in column <= 5 now, check for continuation char
+             ;; If we are in column <= 5 now, check for continuation char.
              (cond ((= 5 (current-column)) (forward-char 1))
                    ((and (< (current-column) 5)
                          (equal fortran-continuation-string
                                 (char-to-string (following-char)))
                          (forward-char 1))))
-             ;; find out parse-limit from here
+             ;; Find out parse-limit from here.
              (setq end-of-line (line-end-position))
              (setq parse-limit (min where end-of-line))
-             ;; parse max up to comment-start, if non-nil and in current line
+             ;; Parse max up to comment-start, if non-nil and in current line.
              (if comment-start
                  (save-excursion
                    (if (re-search-forward quoted-comment-start end-of-line t)
                        (setq parse-limit (min (point) parse-limit)))))
-             ;; now parse if still in limits
+             ;; Now parse if still in limits.
              (if (< (point) where)
                  (setq parse-state (parse-partial-sexp
                                     (point) parse-limit nil nil parse-state))
                (setq not-done nil))))
-         ;; result is
+         ;; Result.
          (nth 3 parse-state))))))
 
 ;; From old version.
@@ -1632,62 +1825,74 @@ If ALL is nil, only match comments that start in column > 0."
         (bol (line-beginning-position))
         (eol (line-end-position))
         (bos (min eol (+ bol (fortran-current-line-indentation))))
+         ;; If in a string at fill-column, break it either before the
+         ;; initial quote, or at fill-col (if string is too long).
         (quote
          (save-excursion
            (goto-char bol)
            ;; OK to break quotes on comment lines.
            (unless (looking-at fortran-comment-line-start-skip)
               (let (fcpoint start)
-             (move-to-column fill-column)
-             (when (fortran-is-in-string-p (setq fcpoint (point)))
-                (save-excursion
-                  (re-search-backward "\\S\"\\s\"\\S\"" bol t)
-                  (setq start
-                        (if fortran-break-before-delimiters
-                            (point)
-                          (1+ (point)))))
-                (if (re-search-forward "\\S\"\\s\"\\S\"" eol t)
-                    (backward-char 2))
-                ;; If the current string is longer than 72 - 6 chars,
-                ;; break it at the fill column (else infinite loop).
-                (if (> (- (point) start)
-                       (- fill-column 6 fortran-continuation-indent))
-                    fcpoint
-                  start))))))
+                (move-to-column fill-column)
+                (when (fortran-is-in-string-p (setq fcpoint (point)))
+                  (save-excursion
+                    (re-search-backward "\\S\"\\s\"\\S\"?" bol t)
+                    (setq start
+                          (if fortran-break-before-delimiters
+                              (point)
+                            (1+ (point)))))
+                  (if (re-search-forward "\\S\"\\s\"\\S\"" eol t)
+                      (backward-char 2))
+                  ;; If the current string is longer than (fill-column
+                  ;; - 6) chars, break it at the fill column (else
+                  ;; infinite loop).
+                  (if (> (- (point) start)
+                         (- fill-column 6 fortran-continuation-indent))
+                      fcpoint
+                    start))))))
         ;; Decide where to split the line. If a position for a quoted
         ;; string was found above then use that, else break the line
-        ;; before the last delimiter.
-        ;; Delimiters are whitespace, commas, and operators.
-        ;; Will break before a pair of *'s.
+        ;; before/after the last delimiter.
         (fill-point
          (or quote
              (save-excursion
-               (move-to-column (1+ fill-column))
-                ;; GM Make this a defcustom as in f90-mode? Add ", (?
-               (skip-chars-backward "^ \t\n,'+-/*=)"
-;;;             (if fortran-break-before-delimiters
-;;;                 "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)")
-                )
-               (when (<= (point) (1+ bos))
+                ;; If f-b-b-d is t, have an extra column to play with,
+                ;; since delimiter gets shifted to new line.
+                (move-to-column (if fortran-break-before-delimiters
+                                    (1+ fill-column)
+                                  fill-column))
+                (let ((repeat t))
+                  (while repeat
+                    (setq repeat nil)
+                    ;; Adapted from f90-find-breakpoint.
+                    (re-search-backward fortran-break-delimiters-re bol)
+                    (if (not fortran-break-before-delimiters)
+                        (if (looking-at fortran-no-break-re)
+                            ;; Deal with cases such as "**" split over
+                            ;; fill-col. Simpler alternative would be
+                            ;; to start from (1- fill-column) above.
+                            (if (> (+ 2 (current-column)) fill-column)
+                                (setq repeat t)
+                              (forward-char 2))
+                          (forward-char 1))
+                      (backward-char)
+                      (or (looking-at fortran-no-break-re)
+                          (forward-char)))))
+                ;; Line indented beyond fill-column?
+               (when (<= (point) bos)
                   (move-to-column (1+ fill-column))
-                  ;;what is this doing???
+                  ;; What is this doing???
                   (or (re-search-forward "[\t\n,'+-/*)=]" eol t)
                       (goto-char bol)))
                (if (bolp)
-                   (re-search-forward "[ \t]" opoint t)
-                 (backward-char)
-                 (if (looking-at "\\s\"")
-                     (forward-char)
-                   (skip-chars-backward " \t\*")))
-               (if fortran-break-before-delimiters
-                   (point)
-                 (1+ (point)))))))
-    ;; if we are in an in-line comment, don't break unless the
+                   (re-search-forward "[ \t]" opoint t))
+                (point)))))
+    ;; If we are in an in-line comment, don't break unless the
     ;; line of code is longer than it should be. Otherwise
     ;; break the line at the column computed above.
     ;;
-    ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s
-    ;; don't prevent a break.
+    ;; Need to use fortran-find-comment-start-skip to make sure that
+    ;; quoted !'s don't prevent a break.
     (when (and (save-excursion
                 (beginning-of-line)
                 (if (not (fortran-find-comment-start-skip))
@@ -1716,7 +1921,7 @@ If ALL is nil, only match comments that start in column > 0."
           (if (fortran-find-comment-start-skip)
               (delete-and-extract-region
                (match-beginning 0) (line-end-position))))))
-    ;; Forward line 1 really needs to go to next non white line
+    ;; Forward line 1 really needs to go to next non white line.
     (if (save-excursion (forward-line)
                        (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
        (progn
@@ -1806,7 +2011,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
     ;; We must be inside function body for this to work.
     (fortran-beginning-of-subprogram)
     (let ((case-fold-search t))                ; case-insensitive
-      ;; search for fortran subprogram start
+      ;; Search for fortran subprogram start.
       (if (re-search-forward
            (concat "^[ \t]*\\(program\\|subroutine\\|function"
                    "\\|[ \ta-z0-9*()]*[ \t]+function\\|"
@@ -1816,7 +2021,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
            t)
           (or (match-string-no-properties 2)
               (progn
-                ;; move to EOL or before first left paren
+                ;; Move to EOL or before first left paren.
                 (if (re-search-forward "[(\n]" nil t)
                     (progn (backward-char)
                            (skip-chars-backward " \t"))
@@ -1828,4 +2033,5 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
 
 (provide 'fortran)
 
+;;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04
 ;;; fortran.el ends here