+ ;; 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.")