+\[ ]| { | | | | | | | | \
+\| | | | |}\n"
+ "String displayed above current line by \\[fortran-column-ruler].
+This variable is used in TAB format mode.
+See the variable `fortran-column-ruler-fixed' for fixed format mode."
+ :type 'string
+ :group 'fortran)
+
+(defcustom fortran-analyze-depth 100
+ "Number of lines to scan to identify fixed or TAB format style."
+ :type 'integer
+ :group 'fortran)
+
+(defcustom fortran-break-before-delimiters t
+ "*Non-nil causes filling to break lines before delimiters.
+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
+ :group 'fortran)
+
+\f
+(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
+ "Regexp matching the start of an IF statement.")
+
+(defvar fortran-end-prog-re1
+ "end\
+\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
+\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?"
+ "Regexp possibly matching the end of a subprogram.")
+
+(defvar fortran-end-prog-re
+ (concat "^[ \t0-9]*" fortran-end-prog-re1)
+ "Regexp possibly matching the end of a subprogram, from the line start.
+See also `fortran-end-prog-re1'.")
+
+(defconst fortran-type-types
+ (concat "\\<"
+ (mapconcat 'identity ; " " -> "[ \t]*"
+ (split-string
+ (regexp-opt
+ (let ((simple-types
+ '("character" "byte" "integer" "logical"
+ "none" "real" "complex"
+ "double precision" "double complex"))
+ (structured-types '("structure" "union" "map"))
+ (other-types '("record" "dimension"
+ "parameter" "common" "save"
+ "external" "intrinsic" "data"
+ "equivalence")))
+ (append
+ (mapcar (lambda (x) (concat "implicit " x))
+ simple-types)
+ simple-types
+ (mapcar (lambda (x) (concat "end " x))
+ structured-types)
+ structured-types
+ other-types)) 'paren))
+ "[ \t]*") "\\>")
+ "Regexp matching Fortran types.")
+
+(defvar fortran-font-lock-keywords-1
+ ;; Program, subroutine and function declarations, plus calls.
+ '(("\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|\
+program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
+ (1 font-lock-keyword-face)
+ (2 font-lock-function-name-face nil t)))
+ "Subdued level highlighting for Fortran mode.")
+
+(defvar fortran-font-lock-keywords-2
+ (append fortran-font-lock-keywords-1
+ (list
+ ;; Fontify all type specifiers (must be first - see below).
+ (cons fortran-type-types 'font-lock-type-face)
+ ;; Builtin keywords (except logical, do and goto - see below).
+ (concat "\\<" (regexp-opt
+ '("continue" "format" "end" "enddo"
+ "if" "then" "else" "endif" "elseif"
+ "while" "inquire" "stop" "return"
+ "include" "open" "close" "read"
+ "write" "format" "print" "select" "case"
+ "cycle" "exit" "rewind" "backspace"
+ "where" "elsewhere")
+ 'paren) "\\>")
+ ;; Builtin operators.
+ (concat "\\." (regexp-opt
+ '("and" "or" "not" "lt" "le" "eq" "ge"
+ "gt" "ne" "true" "false")
+ 'paren) "\\.")
+ ;; do/goto keywords and targets, and goto tags.
+ '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
+ (1 font-lock-keyword-face)
+ (2 font-lock-constant-face nil t))
+ '("^ *\\([0-9]+\\)" . font-lock-constant-face)))
+ "Medium level highlighting for Fortran mode.")
+
+(defvar fortran-font-lock-keywords-3
+ (append
+ fortran-font-lock-keywords-1
+ ;; All type specifiers plus their declared items.
+ (list
+ (list (concat fortran-type-types "[ \t(/]*\\(*\\)?")
+ ;; Type specifier.
+ '(1 font-lock-type-face)
+ ;; Declaration item (or just /.../ block name).
+ `(font-lock-match-c-style-declaration-item-and-skip-to-next
+ ;; Start after any *(...) expression.
+ (condition-case nil
+ (and (match-beginning ,(1+ (regexp-opt-depth
+ fortran-type-types)))
+ (forward-sexp)
+ (forward-sexp))
+ (error nil))
+ ;; No need to clean up.
+ nil
+ ;; Fontify as a variable name, functions fontified elsewhere.
+ (1 font-lock-variable-name-face nil t))))
+ ;; Things extra to `fortran-font-lock-keywords-3' (must be done first).
+ (list
+ ;; Goto-like `err=label'/`end=label' in read/write statements.
+ '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?"
+ (1 font-lock-keyword-face) (4 font-lock-constant-face nil t))
+ ;; Standard continuation character and in a TAB-formatted line.
+ '("^ \\{5\\}\\([^ 0\n]\\)" 1 font-lock-string-face)
+ '("^\t\\([1-9]\\)" 1 font-lock-string-face))
+ `((,fortran-directive-re (0 font-lock-keyword-face t)))
+ ;; `fortran-font-lock-keywords-2' without types (see above).
+ (cdr (nthcdr (length fortran-font-lock-keywords-1)
+ 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
+;; standard comment will throw fontification off on the wrong track.
+;; So we do syntactic fontification with regexps.
+(defvar fortran-font-lock-syntactic-keywords
+ '(("^[cd\\*]" 0 (11))
+ ("^[^cd\\*\t\n].\\{71\\}\\([^\n]+\\)" 1 (11)))
+ "`font-lock-syntactic-keywords' for Fortran.
+These get fixed-format comments fontified.")
+
+(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
+ "Default expressions to highlight in Fortran mode.")
+
+(defvar fortran-imenu-generic-expression
+ ;; These patterns could be confused by sequence nos. in cols 72+ and
+ ;; don't allow continuations everywhere.
+ (list
+ (list
+ nil
+ ;; [This will be fooled by `end function' allowed by G77. Also,
+ ;; it assumes sensible whitespace is employed.]
+ (concat
+ ;; leading whitespace:
+ "^\\s-+\\("
+ ;; function declaration with optional type, e.g. `real',
+ ;; `real*4', character(*), `double precision':
+ "\\(\\sw\\|\\s-\\|[*()+]\\)*"
+ "\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)"
+ ;; Possible statement continuation:
+ "[ \t" fortran-continuation-string "]+"
+ ;; Variable to index:
+ "\\(\\sw+\\)")
+ 3)
+ ;; Un-named block data.
+ '(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)))
+ ;; We might like `;' to be punctuation (g77 multi-statement
+ ;; lines), but that screws abbrevs.
+ (modify-syntax-entry ?\; "w" table)
+ (modify-syntax-entry ?\r " " table)
+ (modify-syntax-entry ?+ "." table)
+ (modify-syntax-entry ?- "." table)
+ (modify-syntax-entry ?= "." table)
+ (modify-syntax-entry ?* "." table)
+ (modify-syntax-entry ?/ "." table)
+ (modify-syntax-entry ?\' "\"" table)
+ (modify-syntax-entry ?\" "\"" table)
+ ;; 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.
+ (modify-syntax-entry ?. "_" table) ; e.g. `a.ne.b'
+ (modify-syntax-entry ?_ "_" table)
+ (modify-syntax-entry ?$ "_" table) ; esp. VMSisms
+ (modify-syntax-entry ?\! "<" table)
+ (modify-syntax-entry ?\n ">" table)
+ 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)
+ (define-key map "\C-c\C-p" 'fortran-previous-statement)
+ (define-key map "\C-c\C-n" 'fortran-next-statement)
+ (define-key map "\C-c\C-d" 'fortran-join-line) ; like f90
+ (define-key map "\M-^" 'fortran-join-line) ; subvert delete-indentation
+ (define-key map "0" 'fortran-electric-line-number)
+ (define-key map "1" 'fortran-electric-line-number)
+ (define-key map "2" 'fortran-electric-line-number)
+ (define-key map "3" 'fortran-electric-line-number)
+ (define-key map "4" 'fortran-electric-line-number)
+ (define-key map "5" 'fortran-electric-line-number)
+ (define-key map "6" 'fortran-electric-line-number)
+ (define-key map "7" 'fortran-electric-line-number)
+ (define-key map "8" 'fortran-electric-line-number)
+ (define-key map "9" 'fortran-electric-line-number)
+
+ (easy-menu-define fortran-menu map "Menu for Fortran mode."
+ `("Fortran"
+ ["Manual" (info "(emacs)Fortran")]
+ ("Customization"
+ ,(custom-menu-create 'fortran)
+ ["Set" Custom-set t]
+ ["Save" Custom-save t]
+ ["Reset to Current" Custom-reset-current t]
+ ["Reset to Saved" Custom-reset-saved t]
+ ["Reset to Standard Settings" Custom-reset-standard t]
+ )
+ "--"
+ ["Comment Region" fortran-comment-region mark-active]
+ ["Uncomment Region"
+ (fortran-comment-region (region-beginning) (region-end) 1)
+ mark-active]
+ ["Indent Region" indent-region mark-active]
+ ["Indent Subprogram" fortran-indent-subprogram t]
+ "--"
+ ["Beginning of Subprogram" fortran-beginning-of-subprogram t]
+ ["End of Subprogram" fortran-end-of-subprogram t]
+ ("Mark"
+ ["Subprogram" mark-defun t]
+ ["IF Block" fortran-mark-if t]
+ ["DO Block" fortran-mark-do t]
+ )
+ ["Narrow to Subprogram" narrow-to-defun t]
+ ["Widen" widen t]
+ "--"
+ ["Temporary column ruler" fortran-column-ruler t]
+ ["72-column window" fortran-window-create t]
+ ["Full Width Window"
+ (enlarge-window-horizontally (- (frame-width) (window-width)))
+ (< (window-width) (frame-width))]
+ ["Momentary 72-column window" fortran-window-create-momentarily t]
+ "--"
+ ["Break Line at Point" fortran-split-line t]
+ ["Join Line" fortran-join-line t]
+ ["Fill Statement/Comment" fill-paragraph t]
+ "--"
+ ["Toggle auto-fill" auto-fill-mode :selected auto-fill-function
+ :style toggle]
+ ["Toggle abbrev-mode" abbrev-mode :selected abbrev-mode
+ :style toggle]
+ ["Add imenu Menu" imenu-add-menubar-index
+ :active (not (lookup-key (current-local-map) [menu-bar index]))
+ :included (fboundp 'imenu-add-to-menubar)]))
+ map)