;;; fortran.el --- Fortran mode for GNU Emacs
-;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 2001
+;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 01, 03, 04
;; Free Software Foundation, Inc.
;; Author: Michael D. Prange <prange@erl.mit.edu>
;; * 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))
:type 'boolean
:group 'fortran-indent)
-(defcustom fortran-tab-mode-string " TAB"
- "*String to appear in mode line in TAB format buffers.
-Should have a leading space."
+(defcustom fortran-tab-mode-string "/t"
+ "*String to appear in mode line in TAB format buffers."
:type 'string
:group 'fortran-indent)
-(defvar fortran-tab-mode-minor-mode-string nil
- "Internal variable used for `minor-mode-alist' in Fortran mode.
-Do not change the value of this variable - edit `fortran-tab-mode-string'
-instead.")
-(make-variable-buffer-local 'fortran-tab-mode-minor-mode-string)
-
-(add-to-list 'minor-mode-alist
- '(fortran-tab-mode-minor-mode-string
- (indent-tabs-mode fortran-tab-mode-minor-mode-string)))
-
(defcustom fortran-do-indent 3
"*Extra indentation applied to DO blocks."
:type 'integer
(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
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)
(set (make-local-variable 'comment-indent-function) 'fortran-comment-indent)
(set (make-local-variable 'abbrev-all-caps) t)
(set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
- (setq fortran-tab-mode-minor-mode-string fortran-tab-mode-string)
(set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format))
+ (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
(set (make-local-variable 'fill-column) 72)
(set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
(set (make-local-variable 'font-lock-defaults)
(set (make-local-variable 'add-log-current-defun-function)
#'fortran-current-defun)
(set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
+ (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
(run-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
(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.
(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)))
"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."
(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
(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.
(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
(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")
(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")
(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))
(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))
(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
(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)
(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
(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")
((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?
(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.
(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 72 - 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))
(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
(cond
((eq (char-after) ?\t) t)
((looking-at " \\{6\\}") nil)
- (fortran-tab-mode-default t)
- (t nil)))))
+ (t fortran-tab-mode-default)))))
(defun fortran-fill-paragraph (&optional justify)
"Fill surrounding comment block as paragraphs, else fill statement.
;; 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\\|"
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"))
(provide 'fortran)
+;;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04
;;; fortran.el ends here