;;; ==================================================================== ;;; @Emacs-Lisp-file{ ;;; author = "Nelson H. F. Beebe", ;;; version = "0.15", ;;; date = "01 May 1994", ;;; time = "13:38:57 MDT", ;;; filename = "sftran3.el", ;;; address = "Center for Scientific Computing ;;; Department of Mathematics ;;; University of Utah ;;; Salt Lake City, UT 84112 ;;; USA", ;;; telephone = "+1 801 581 5254", ;;; FAX = "+1 801 581 4148", ;;; checksum = "63943 1930 7274 72324", ;;; email = "beebe@math.utah.edu (Internet)", ;;; codetable = "ISO/ASCII", ;;; keywords = "emacs, sftran3", ;;; supported = "yes", ;;; docstring = "This file provides an mode for editing ;;; SFTRAN3 source code. SFTRAN3 is a ;;; structured Fortran preprocessor developed ;;; at the Jet Propulsion Laboratory, Pasadena, ;;; CA, USA, in the mid 1970s, and used ;;; extensively at the author's site. ;;; ;;; This code is based on DEC-20 Emacs SFTRAN3 ;;; editing support in TECO originally written ;;; by the author in 1983. This new version in ;;; Emacs Lisp is a redesign with extended ;;; functionality. ;;; ;;; The checksum field above contains a CRC-16 ;;; checksum as the first value, followed by the ;;; equivalent of the standard UNIX wc (word ;;; count) utility output of lines, words, and ;;; characters. This is produced by Robert ;;; Solovay's checksum utility.", ;;; } ;;; ==================================================================== ;;; sftran3.el --- major mode for editing SFTRAN3 (structured Fortran) code ;; Author: Nelson H. F. Beebe ;; Created: 14-Feb-1990 ;; Version: 0.13 ;; Keywords: sftran3, sf3, structured Fortran ;; Copyright (C) 1993 Free Software Foundation, Inc. ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA. ;;; Commentary: ;;====================================================================== ;; This file contains editing support for the SFTRAN3 language, a ;; Fortran preprocessor developed at the Jet Propulsion Laboratory in ;; the late 1970s, and used for most of the author's graphics ;; system. The editing support here was originally developed as TOPS-20 ;; EMACS TECO libraries, sftran.emacs (1430 lines) and fortran.emacs ;; (5048 lines), from May 1981 to Nov 1984 (Fortran) and May 1983 ;; (SFTRAN3), with minor edits applied up to May 1986. Both TECO ;; libraries have been stable since that time. ;; ;; The existence of that base of code, and the relative ease of Lisp ;; programming compared to TECO programming, and the availability of ;; regular-expression matching in GNU Emacs Lisp, made it possible to ;; code and debug the first complete draft of sftran.el of about 850 ;; lines in 3 evenings. ;; ;; In order to preserve maximum correspondence between the two ;; systems, I have chosen to preserve similar function names, and key ;; bindings, except that the later have moved from the C-Z prefix to ;; the C-C prefix. C-C is not used by standard GNU Emacs editing ;; modes, and its availability opens up 128 binding slots that with ;; TOPS-20 Emacs were already partly in use. ;; ;; Essentially all user-callable functions in this library have key ;; bindings. Functions which are intended to be called only from ;; other functions have documentation strings that begin "INTERNAL:". ;; ;; In developing this library, I have also borrowed heavily from my ;; latex.el for LaTeX editing support. ;;====================================================================== ;;; Change log: ;; [01-May-1994] 0.15 ;; Move menu-bar defvars out of sftran3-x-window-setup, and ;; rename their prefixes from menu-bar-sf3 to sftran3-menu-bar, ;; to conform to conventions of this file. Also, add an fset to ;; make sf3-mode an alias for sftran3-mode. ;; ;; [20-Apr-1994] 0.14 ;; Add new variable sftran3-mode-syntax-table and new functions ;; sftran3-abbrev-help, sftran3-abbrev-start, sftran3-close, ;; sftran3-directive, sftran3-else, sftran3-endif, sftran3-external, ;; sftran3-function-abbrev, sftran3-function-menu, sftran3-include, ;; sftran3-indent, sftran3-inline, sftran3-inquire, sftran3-intrinsic, ;; sftran3-lineup, sftran3-noindent, sftran3-pause, sftran3-print, ;; sftran3-program, sftran3-open, sftran3-stet, and sftran3-version. ;; The new abbrev functions are adapted from the standard fortran.el ;; file, but instead of expanding to fixed strings, they invoke the ;; more powerful sftran3-xxx functions. Also provide new default key ;; bindings for sftran3-close, sftran3-open, sftran3-inquire, and ;; sftran3-abbrev-start. ;; ;; Update sftran3-implicit to prompt for a data type, then supply a ;; complete implicit statement template with point inside the ;; parentheses. ;; ;; Change completing-read calls for Fortran data types to not require ;; a match, for those rare times when a length modifier must be ;; supplied as well. ;; ;; Change sftran3-mode to omit sftran3-mode-version from the mode ;; line, and instead invoke sftran3-version to display the version ;; number on startup. ;; ;; Greatly extend sftran3-default-abbrev-table with many new ;; abbreviations borrowed from fortran-mode, and set the syntax table ;; to sftran3-mode-syntax-table so that abbreviations that begin with ;; special characters are handled properly. ;; ;; Move a few declaration-section statements from sf3-stmt menu to ;; sf3-decl menu, and add several new menu items to sf3-misc menu. ;; ;; [18-Apr-1994] 0.13 ;; Add new functions sftran3-{close,inquire,open}-{short,long}, ;; sftran3-end-file, and sftran3-rewind, and install in sf3-stmt menu. ;; Add forgotten sftran3-character to sf3-decl menu, and sftran3-procedure ;; to sf3-stmt menu. ;; ;; [07-Sep-1993] 0.12 ;; Move menu-bar support into sftran3-x-environment and invoke it from ;; sftran3-mode. Merge in replacements for several functions from ;; separate experiments. Add sftran3-indent-new-comment-line to ;; improve comment entry. Add sftran3-open-line, because emacs ;; version 19 open-line no longer works as needed here. ;; ;; [15-Jun-1993] 0.11 ;; Update for Emacs 19. Add menu-bar support when loaded under a ;; window system, replacing old optional sf3-menu.el used in Emacs ;; 18. Revise comment structure to match the standards described in ;; info node elisp -> tips -> library headers. Add function ;; sftran3-define-key and variable sftran3-command-key-prefix so that ;; the old C-c prefix can be easily changed by those who wish to do ;; so. Reformat functions according to guidelines in info node elisp ;; -> tips -> style tips. ;; ;; [26-May-1992] 0.10 ;; Minor fixes. ;; ;; [05-May-1992] 0.09 ;; Add sftran3-lowercase-keywords variable and update sftran3-statement ;; to use it. ;; ;; [28-Jan-1991] 0.08 ;; General polishing, debugging, and testing. Minor key-binding ;; modifications. Add several new functions: ;; sftran3-newline-and-indent, ;; sftran3-tab, ;; sftran3-token-add, ;; sftran3-token-divide, ;; sftran3-token-multiply, ;; sftran3-token-operator, ;; sftran3-token-subtract, ;; ;; [03-Dec-1990] 0.07 ;; Make sftran3-previous-level and sftran3-next-level supply new ;; indentation. ;; ;; [01-Dec-1990] 0.06 ;; Add arg support to sftran3-character. ;; ;; [25-Jul-1990] 0.05 ;; Add missing trailing newlines on some statements. ;; ;; [21-Jul-1990] 0.04 ;; Add sftran3-kill-indentation. ;; Add sftran3-hollerith. Improve sftran3-indent-line to handle ;; successive indentation requests. ;; ;; [20-Jul-1990] 0.03 ;; Add return, stop, do-procedure functions. ;; ;; [22-Feb-1990] 0.02 ;; Minor fixes. ;; ;; [18-Feb-1990] 0.01 ;; Complete implementation. ;; ;; [14-Feb-1990] 0.00 ;; First basic implementation. ;;; Code: ;;; Please keep the functions sorted ALPHABETICALLY (M-x sort-pages ;;; does the trick). ;;; (setq completion-ignore-case t) ;function type matches are case insensitive (defvar sftran3-author-email-address "beebe@math.utah.edu" "E-mail address of the author of GNU Emacs sftran3-mode editing mode support. Used by sftran3-gripe for mailing bug reports and comments.") (defvar sftran3-case-number 0 "Current CASE number.") (defvar sftran3-column-indentation 6 "Current statement column indentation, less 1.") (defvar sftran3-command-key-prefix "\C-c" "*Prefix keystroke(s) to be applied to sftran3 mode key bindings. Emacs standards require that C-c be reserved for user-specific bindings, but sftran3-mode has historically used C-c prefix key. You can set this variable to \"\\C-c\" for old-style binding, or to say, \"\\C-z\" or \"\\C-c\\C-c\" for standard-conforming binding.") (defvar sftran3-comment-start nil "*String that starts an SFTRAN3 comment.") (setq sftran3-comment-start "C$") (defvar sftran3-comment-start-regexp nil "*Regular expression that matches the start of a comment.") (setq sftran3-comment-start-regexp "^[*Cc]") (defvar sftran3-continuation-prefix nil "*Continuation line prefix.") (setq sftran3-continuation-prefix " X") (defvar sftran3-declaration-start 27 "*Column in which declaration statement variable lists begin.") (defconst sftran3-default-comment-prefix "C$ " "*Comment statement fill prefix.") (defvar sftran3-comment-prefix sftran3-default-comment-prefix "Comment statement fill prefix.") (defvar sftran3-end-routine-regexp nil "*Regular expression that matches the end of a routine.") (setq sftran3-end-routine-regexp "^ [ ]*\\(END[ ]*PROGRAM\\|END\\)[ ]*$") (defvar sftran3-inline-comment nil "*SFTRAN3 INLINE comment flag (1 or 2 characters only).") (setq sftran3-inline-comment "--") (defvar sftran3-level-indentation 5 "*How much to indent each new nested statement level.") (defvar sftran3-lowercase-keywords nil "*If non-nil, insert keywords in lowercase. Normally, they are inserted in uppercase.") ; Originally, these were inside sftran3-x-window-setup, but that ; gave undefined variable errors when executed unless this file ; had been loaded twice, sigh... (if (string-lessp (substring emacs-version 0 2) "19") nil ;; else emacs 19 or later (defvar sftran3-menu-bar-misc-menu (make-sparse-keymap "sf3-misc")) (defvar sftran3-menu-bar-decl-menu (make-sparse-keymap "sf3-decl")) (defvar sftran3-menu-bar-stmt-menu (make-sparse-keymap "sf3-stmt"))) (defvar sftran3-mode-abbrev-table nil "Abbrev table in use in sftran3-mode buffers.") (defvar sftran3-mode-map (make-sparse-keymap) "Keymap used in sftran3 mode.") (defvar sftran3-mode-syntax-table nil "Syntax table in use in sftran3 mode buffers.") ;;; In order for word abbrevs to work with special characters, they ;;; must be reset to be word characters. This particular selection ;;; matches the settings below in the sftran3-mode-abbrev-table. (if sftran3-mode-syntax-table () (setq sftran3-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\! "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\# "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\& "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\; "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\< "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\= "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\> "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\| "w" sftran3-mode-syntax-table) (modify-syntax-entry ?\~ "w" sftran3-mode-syntax-table)) (defvar sftran3-mode-version nil "Version number of current release of sftran3-mode") (setq sftran3-mode-version "beta 0.15 [01-May-1994]") ;(setq sftran3-mode-version "beta 0.14 [20-Apr-1994]") ;(setq sftran3-mode-version "beta 0.13 [18-Apr-1994]") ;(setq sftran3-mode-version "beta 0.12 [06-Sep-1993]") ;(setq sftran3-mode-version "beta 0.11 [15-Jun-1993]") ;(setq sftran3-mode-version "beta 0.10 [26-May-1992]") ;(setq sftran3-mode-version "beta 0.09 [05-May-1992]") ;(setq sftran3-mode-version "beta 0.08 [28-Jan-1991]") (defvar sftran3-procedure-regexp nil "*Regular expression that matches the start of a procedure.") (setq sftran3-procedure-regexp "^ [ ]*PROCEDURE[ ]*(") (defvar sftran3-routine-regexp nil "*Regular expression that matches the start of a function, program, or subroutine.") (setq sftran3-routine-regexp "^ [ ]*\\(SUBROUTINE\\|PROGRAM\\|\\(CHARACTER\\|COMPLEX\\|DOUBLE[ ]*PRECISION\\|INTEGER\\|LOGICAL\\|REAL\\)[*0-9 ]*FUNCTION\\)[ ]*") (defvar sftran3-sort-prefix nil "*Non-SFTRAN3 string used as a prefix for creating a sort tag") (setq sftran3-sort-prefix "\001\002\003") (defconst sftran3-standard-types nil "*Standard function types. Users may also define private ones.") (setq sftran3-standard-types '( ("CHARACTER") ("COMPLEX") ("DOUBLE PRECISION") ("INTEGER") ("LOGICAL") ("REAL"))) (defvar sftran3-statement-label-regexp "^[ 0-9][ 0-9][ 0-9][ 0-9][ 0-9]" "Regular expression that matches a Fortran statement label at the beginning of a line. It also matches blanks in columns 1..5.") (defvar sftran3-structure-label-regexp "^ [^ \n\t][^\n:]*:" "Regular expression that matches an SFTRAN3 structure label at the beginning of a line.") (defvar sftran3-token-regexp nil "*Regular expression matching a Fortran or SFTRAN3 token (scalar variable, or array or function reference).") (setq sftran3-token-regexp "[A-Za-z0-9_$]+[ ]*([^)]*)\\|[A-Za-z0-9$_]+") (defun sftran3-abbrev-start () "Typing ;\\[help-command] or ;? lists all the sftran3 abbrevs. Any other key combination is executed normally." (interactive) (let (c) (insert last-command-char) (if (or (eq (setq c (read-event)) ??) ;insert char if not equal to `?' (eq c help-char)) (sftran3-abbrev-help) (setq unread-command-events (list c))))) (defun sftran3-abbrev-help () "List the currently defined abbrevs in Sftran3 mode." (interactive) (message "Listing abbrev table...") (display-buffer (sftran3-prepare-abbrev-list-buffer)) (message "Listing abbrev table...done")) (defun sftran3-back-to-indentation () "INTERNAL: Move to the first non-blank character past an initial label." (sftran3-skip-label) (while (looking-at " ") (forward-char 1))) (defun sftran3-backward-token (&optional arg) "Move backward over ARG tokens (scalars, or array or function references)." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (re-search-backward sftran3-token-regexp nil t arg)) (defun sftran3-begin-newline () "INTERNAL: Start a new line, if point is not already at start of line. Any trailing space on the line is discarded before making the decision." (end-of-line) (delete-horizontal-space) (if (bolp) () (end-of-line) (newline))) (defun sftran3-blanks (n) "INTERNAL: Return an N-character blank string. If N <= 0, return an empty string." (make-string (max 0 n) 32)) (defun sftran3-block-data () "Insert BLOCK DATA () ... END PROGRAM statement block. Invoked by \\\\[sftran3-block-data]." (interactive) (setq sftran3-comment-prefix sftran3-default-comment-prefix) (sftran3-kill-indentation) (sftran3-statement "BLOCK DATA\n") (insert sftran3-default-comment-prefix "()\n") (insert sftran3-default-comment-prefix) (sftran3-date-edit) (insert "INLINE(" sftran3-inline-comment ")\n") (sftran3-statement "END PROGRAM\n") (search-backward "BLOCK DATA") (forward-char 10)) (defun sftran3-case-decrement () "Decrement current CASE number. Invoked by \\\\[sftran3-case-decrement]." (interactive) (setq sftran3-case-number (max 1 (1- sftran3-case-number)))) (defun sftran3-case-increment () "Increment current CASE number. Invoked by \\\\[sftran3-case-increment]." (interactive) (setq sftran3-case-number (max 1 (1+ sftran3-case-number)))) (defun sftran3-case-k () "Insert CASE k statement, where the case number is determined automatically from the current value of sftran3-case-number. Invoked by \\\\[sftran3-case-k]." (interactive) (sftran3-case-increment) (sftran3-previous-level) (sftran3-statement (format "CASE %d" sftran3-case-number)) (sftran3-next-level) (sftran3-statement "")) (defun sftran3-case-renumber () "With point inside, or after, a DO CASE ... END CASE statement, renumber the cases in ascending order, starting from 1. Nested CASE statements are not handled. Invoked by \\\\[sftran3-case-renumber]." (interactive) (let ((n) (case-start) (case-end)) (re-search-backward "^[ ]*DO[ ]*CASE") (beginning-of-line) (setq case-start (point)) (re-search-forward "END[ ]*CASE") (forward-line 1) (setq case-end (point)) (narrow-to-region case-start case-end) (goto-char (point-min)) (setq n 0) (while (re-search-forward "^[ ]*CASE[ ]*[0-9]" nil t) (backward-char 1) (kill-word 1) (setq n (1+ n)) (insert (format "%d" n))) (setq sftran3-case-number n)) (goto-char (point-min)) (widen)) (defun sftran3-collapse-statement () "Collapse a continued statement into a single long line, deleting leading indentation from continuation lines. Auto-fill can restore it to proper form after editing. Invoked by \\\\[sftran3-collapse-statement]." (interactive) (save-excursion (forward-line 1) (while (looking-at "^ [^ 0]") (delete-char -1) ;delete continuation prefix (delete-char 6) (just-one-space) ;and remove old indentation (forward-line 1)))) (defun sftran3-character (&optional arg) "Insert CHARACTER declaration. An argument sets the length field, and a 0 argument generates a *(*) length field. Invoked by \\\\[sftran3-character]." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (sftran3-declaration (cond ((= arg 1) "CHARACTER") ((<= arg 0) "CHARACTER*(*)") (t (format "CHARACTER*%d" arg))))) (defun sftran3-close (&optional arg) "Insert CLOSE statement in either the short form (no argument), or the long form (with an argument)." (interactive) (if (or (not (null arg)) (not (null current-prefix-arg))) (sftran3-close-long) ;then had argument (sftran3-close-short))) ;else no argument (defun sftran3-close-long () "Insert CLOSE statement (long form). Invoked by \\\\[sftran3-close-long]." (interactive) (let ((sep (concat ",\n" sftran3-continuation-prefix (sftran3-blanks sftran3-column-indentation)))) (sftran3-statement (concat "CLOSE (UNIT = " sep "ERR = label" sep "IOSTAT = intvar" sep "STATUS = '')"))) (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-close-short () "Insert CLOSE statement (short form). Invoked by \\\\[sftran3-close-short]." (interactive) (sftran3-statement "CLOSE (UNIT = )") (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-common () "Insert COMMON declaration. Invoked by \\\\[sftran3-common]." (interactive) (sftran3-declaration "COMMON / /") (search-backward "/")) (defun sftran3-complex () "Insert COMPLEX declaration. Invoked by \\\\[sftran3-complex]." (interactive) (sftran3-declaration "COMPLEX")) (defun sftran3-convert-comments () "Change Fortran comments to SFTRAN3 comments to preserve their indentation. Invoked by \\\\[sftran3-convert-comments]. " (interactive) (goto-char (point-min)) (replace-regexp (concat sftran3-comment-start-regexp "$") sftran3-comment-start) (goto-char (point-min)) (replace-regexp (concat sftran3-comment-start-regexp ".") sftran3-comment-start) (goto-char (point-min))) (defun sftran3-cycle () "Insert CYCLE statement. Invoked by \\\\[sftran3-cycle]." (interactive) (sftran3-statement "CYCLE ")) (defun sftran3-data () "Insert DATA declaration. Invoked by \\\\[sftran3-data]." (interactive) (sftran3-declaration "DATA")) ;; Adapted from function date in clsc.el to allow independent distribution ;; of sftran3.el (defun sftran3-date (&optional open-char close-char) "Insert current date at point in format [18-Aug-1990], leaving point after the insertion. The optional arguments can specify alternatives to the open and close bracket delimiters." (interactive) (let ((cts (current-time-string))) ;get "Tue Feb 9 17:06:20 1988" ; 0123456789.123456789.1234 (insert (if open-char open-char "[") (if (equal (substring cts 8 9) " ") "0" (substring cts 8 9)) (substring cts 9 10) ;get "dd" "-" (substring cts 4 7) "-" ;get "-mon-" (substring cts 20 24) ;get "yyyy" (if close-char close-char "]")))) ;end with "[dd-mon-yyyy]" (defun sftran3-date-edit () "Insert comment statement with date stamp. Invoked by \\\\[sftran3-date-edit]." (interactive) (sftran3-begin-newline) (insert sftran3-comment-prefix) (sftran3-date "(" ")\n")) (defun sftran3-declaration (declaration) "INTERNAL: Insert DECLARATION following point, blank filling to sftran3-declaration-start column." (sftran3-kill-indentation) (sftran3-statement declaration) (insert (sftran3-blanks (- (1- sftran3-declaration-start) (current-column))))) (defun sftran3-default-abbrev-table () "Define default abbreviation table for sftran3-mode." (interactive) (set-syntax-table sftran3-mode-syntax-table) (setq abbrevs-changed t) (define-abbrev-table 'sftran3-mode-abbrev-table ()) ;; NB: abbrevs that begin with special characters will work ONLY if ;; the syntax-table entries for those characters are changed to word ;; syntax. See the initialization of sftran3-mode-syntax-table above. (define-abbrev sftran3-mode-abbrev-table "&" ".AND." nil) (define-abbrev sftran3-mode-abbrev-table "&&" ".AND." nil) (define-abbrev sftran3-mode-abbrev-table "|" ".OR." nil) (define-abbrev sftran3-mode-abbrev-table "||" ".OR." nil) (define-abbrev sftran3-mode-abbrev-table "<" ".LT." nil) (define-abbrev sftran3-mode-abbrev-table ">" ".GT." nil) (define-abbrev sftran3-mode-abbrev-table "#" ".NE." nil) (define-abbrev sftran3-mode-abbrev-table "<>" ".NE." nil) (define-abbrev sftran3-mode-abbrev-table "!=" ".NE." nil) (define-abbrev sftran3-mode-abbrev-table "=<" ".LE." nil) (define-abbrev sftran3-mode-abbrev-table "<=" ".LE." nil) (define-abbrev sftran3-mode-abbrev-table "=>" ".GE." nil) (define-abbrev sftran3-mode-abbrev-table ">=" ".GE." nil) (define-abbrev sftran3-mode-abbrev-table "==" ".EQ." nil) (define-abbrev sftran3-mode-abbrev-table "~" ".NOT." nil) (define-abbrev sftran3-mode-abbrev-table ";fmt" "FORMAT ()" nil) ;; new abbrevs adapted from fortran-mode, with some deletions of ;; non-SFTRAN3 statements and non-standard Fortran (define-abbrev sftran3-mode-abbrev-table ";bd" "" 'sftran3-block-data) (define-abbrev sftran3-mode-abbrev-table ";ch" "" 'sftran3-character) (define-abbrev sftran3-mode-abbrev-table ";cl" "" 'sftran3-close) (define-abbrev sftran3-mode-abbrev-table ";cm" "" 'sftran3-common) (define-abbrev sftran3-mode-abbrev-table ";cx" "" 'sftran3-complex) (define-abbrev sftran3-mode-abbrev-table ";dp" "" 'sftran3-double-precision) (define-abbrev sftran3-mode-abbrev-table ";e" "" 'sftran3-else) (define-abbrev sftran3-mode-abbrev-table ";el" "" 'sftran3-else-if-then) (define-abbrev sftran3-mode-abbrev-table ";en" "" 'sftran3-end-if) (define-abbrev sftran3-mode-abbrev-table ";eq" "" 'sftran3-equivalence) (define-abbrev sftran3-mode-abbrev-table ";ex" "" 'sftran3-external) (define-abbrev sftran3-mode-abbrev-table ";f" "" 'sftran3-format) (define-abbrev sftran3-mode-abbrev-table ";fa" ".false." nil) (define-abbrev sftran3-mode-abbrev-table ";fu" "" 'sftran3-function-menu) (define-abbrev sftran3-mode-abbrev-table ";im" "" 'sftran3-implicit) (define-abbrev sftran3-mode-abbrev-table ";inc" "" 'sftran3-include) (define-abbrev sftran3-mode-abbrev-table ";in" "" 'sftran3-integer) (define-abbrev sftran3-mode-abbrev-table ";int" "" 'sftran3-intrinsic) (define-abbrev sftran3-mode-abbrev-table ";l" "" 'sftran3-logical) (define-abbrev sftran3-mode-abbrev-table ";n" "" 'sftran3-namelist) (define-abbrev sftran3-mode-abbrev-table ";o" "" 'sftran3-open) (define-abbrev sftran3-mode-abbrev-table ";pa" "" 'sftran3-parameter) (define-abbrev sftran3-mode-abbrev-table ";pr" "" 'sftran3-program) (define-abbrev sftran3-mode-abbrev-table ";ps" "" 'sftran3-pause) (define-abbrev sftran3-mode-abbrev-table ";p" "" 'sftran3-print) (define-abbrev sftran3-mode-abbrev-table ";re" "" 'sftran3-real) (define-abbrev sftran3-mode-abbrev-table ";r" "" 'sftran3-read) (define-abbrev sftran3-mode-abbrev-table ";rt" "" 'sftran3-return) (define-abbrev sftran3-mode-abbrev-table ";rw" "" 'sftran3-rewind) (define-abbrev sftran3-mode-abbrev-table ";s" "" 'sftran3-stop) (define-abbrev sftran3-mode-abbrev-table ";sa" "" 'sftran3-save) (define-abbrev sftran3-mode-abbrev-table ";su" "" 'sftran3-subroutine) (define-abbrev sftran3-mode-abbrev-table ";tr" ".true." nil) (define-abbrev sftran3-mode-abbrev-table ";w" "" 'sftran3-write) nil) ;; NB: this function must appear before references to it! (defun sftran3-define-key (map suffix function) "Define a key binding in MAP, prefixing SUFFIX with sftran3-command-key-prefix, and attach it to FUNCTION." (define-key map (concat sftran3-command-key-prefix suffix) function)) (defun sftran3-default-keymap () "Define default keymap for sftran3-mode." (interactive) (use-local-map sftran3-mode-map) (let ((map (make-sparse-keymap))) (sftran3-define-key map " " 'sftran3-collapse-statement) (sftran3-define-key map "!" 'sftran3-date-edit) (sftran3-define-key map "#" 'sftran3-case-renumber) (sftran3-define-key map "+" 'sftran3-next-level) (sftran3-define-key map "-" 'sftran3-previous-level) (sftran3-define-key map "." 'sftran3-set-fill-prefix) (sftran3-define-key map "/" 'sftran3-forward-token) (sftran3-define-key map ";" 'sftran3-convert-comments) (sftran3-define-key map "B" 'sftran3-block-data) (sftran3-define-key map "C" 'sftran3-character) (sftran3-define-key map "\C-d" 'sftran3-do-procedure) (sftran3-define-key map "D" 'sftran3-double-precision) (sftran3-define-key map "E" 'sftran3-equivalence) (sftran3-define-key map "F" 'sftran3-function) (sftran3-define-key map "G" 'sftran3-gripe) (sftran3-define-key map "H" 'sftran3-hollerith) (sftran3-define-key map "I" 'sftran3-integer) (sftran3-define-key map "K" 'sftran3-close) (sftran3-define-key map "L" 'sftran3-logical) (sftran3-define-key map "M" 'sftran3-common) (sftran3-define-key map "N" 'sftran3-namelist) (sftran3-define-key map "O" 'sftran3-open) (sftran3-define-key map "P" 'sftran3-parameter) (sftran3-define-key map "Q" 'sftran3-inquire) (sftran3-define-key map "R" 'sftran3-real) (sftran3-define-key map "S" 'sftran3-subroutine) (sftran3-define-key map "X" 'sftran3-complex) (sftran3-define-key map "\\" 'sftran3-backward-token) (sftran3-define-key map "\C-c+" 'sftran3-token-add) (sftran3-define-key map "\C-c-" 'sftran3-token-subtract) (sftran3-define-key map "\C-c*" 'sftran3-token-multiply) (sftran3-define-key map "\C-c/" 'sftran3-token-divide) (sftran3-define-key map "\C-c>" 'sftran3-case-increment) (sftran3-define-key map "\C-c<" 'sftran3-case-decrement) (sftran3-define-key map "\C-f" 'sftran3-format) (sftran3-define-key map "\C-i" 'sftran3-indent-line) (sftran3-define-key map "\C-n" 'sftran3-news) (sftran3-define-key map "\C-pp" 'sftran3-paginate-procedures) (sftran3-define-key map "\C-pr" 'sftran3-paginate-routines) (sftran3-define-key map "\C-pu" 'sftran3-unpaginate) (sftran3-define-key map "\C-r" 'sftran3-read) (sftran3-define-key map "\C-sp" 'sftran3-sort-procedures) (sftran3-define-key map "\C-sr" 'sftran3-sort-routines) (sftran3-define-key map "\C-st" 'sftran3-sort-tokens) (sftran3-define-key map "\C-w" 'sftran3-write) (sftran3-define-key map "b" 'sftran3-do-block) (sftran3-define-key map "c" 'sftran3-do-case) (sftran3-define-key map "d" 'sftran3-data) (sftran3-define-key map "e" 'sftran3-else-if-then) (sftran3-define-key map "f" 'sftran3-do-for) (sftran3-define-key map "h" 'sftran3-hollerith) (sftran3-define-key map "i" 'sftran3-if-then) (sftran3-define-key map "j" 'sftran3-if) (sftran3-define-key map "k" 'sftran3-case-k) (sftran3-define-key map "l" 'sftran3-label) (sftran3-define-key map "n" 'sftran3-namelist) (sftran3-define-key map "o" 'sftran3-do-forever) (sftran3-define-key map "p" 'sftran3-procedure) (sftran3-define-key map "r" 'sftran3-return) (sftran3-define-key map "s" 'sftran3-stop) (sftran3-define-key map "t" 'sftran3-function) (sftran3-define-key map "u" 'sftran3-do-until) (sftran3-define-key map "w" 'sftran3-do-while) (define-key map "\C-i" 'sftran3-tab) (define-key map "\C-o" 'sftran3-open-line) (define-key map "\C-x." 'sftran3-set-fill-prefix) (define-key map "\C-j" 'sftran3-newline-and-indent) (define-key map ";" 'sftran3-abbrev-start) (define-key esc-map "\C-j" 'sftran3-indent-new-comment-line) (setq sftran3-mode-map map))) (defun sftran3-directive (directive) "INTERNAL: Insert DIRECTIVE following point, beginning in column 1." (sftran3-kill-indentation) (beginning-of-line) (insert directive)) (defun sftran3-do-block () "Insert DO BLOCK ... END BLOCK Statement. Invoked by \\\\[sftran3-do-block]." (interactive) (sftran3-insert-block "DO BLOCK" "END BLOCK" "DO BLOCK\n[ ]*")) (defun sftran3-do-case () "Insert DO CASE () ... END CASE Statement. Invoked by \\\\[sftran3-do-case]." (interactive) (setq sftran3-case-number 0) (sftran3-statement "DO CASE ()") (sftran3-next-case) (sftran3-next-case) (sftran3-next-case) (sftran3-statement "CASE OTHER") (sftran3-statement "END CASE") (search-backward "CASE 1") (sftran3-statement "?") (sftran3-next-level) (if (looking-at "[?]") (delete-char 1)) (delete-blank-lines) (search-backward ")") ) (defun sftran3-do-for () "Insert DO FOR ... END FOR Statement. Invoked by \\\\[sftran3-do-for]." (interactive) (sftran3-insert-block "DO FOR" "END FOR" "DO FOR") (insert " ")) (defun sftran3-do-forever () "Insert DO FOREVER () ... END FOREVER Statement. Invoked by \\\\[sftran3-do-forever]." (interactive) (sftran3-insert-block "DO FOREVER" "END FOREVER" "DO FOREVER\n[ ]*")) (defun sftran3-do-until () "Insert DO UNTIL () ... END UNTIL Statement. Invoked by \\\\[sftran3-do-until]." (interactive) (sftran3-insert-block "DO UNTIL ()" "END UNTIL" "(")) (defun sftran3-do-while () "Insert DO WHILE () ... END WHILE Statement. Invoked by \\\\[sftran3-do-while]." (interactive) (sftran3-insert-block "DO WHILE ()" "END WHILE" "(")) (defun sftran3-do-procedure () "Insert DO () statement. Invoked by \\\\[sftran3-do-procedure]." (interactive) (sftran3-statement "DO ()") (backward-char 1)) (defun sftran3-double-precision () "Insert DOUBLE PRECISION declaration. Invoked by \\\\[sftran3-double-precision]." (interactive) (sftran3-declaration "DOUBLE PRECISION")) (defun sftran3-else () "Insert ELSE statement. Invoked by \\\\[sftran3-else]." (interactive) (sftran3-statement "ELSE\n")) (defun sftran3-else-if-then () "Insert ELSE IF () THEN statement. Invoked by \\\\[sftran3-else-if-then]." (interactive) (sftran3-statement "ELSE IF () THEN") (search-backward ")")) (defun sftran3-end-file () "Insert END FILE statement. Invoked by \\\\[sftran3-end-file]." (interactive) (sftran3-statement "END FILE ")) (defun sftran3-end-if () "Insert END IF statement. Invoked by \\\\[sftran3-end-if]." (interactive) (sftran3-statement "END IF\n")) (defun sftran3-equivalence () "Insert EQUIVALENCE statement. Invoked by \\\\[sftran3-equivalence]." (interactive) (sftran3-declaration "EQUIVALENCE") (insert "()") (backward-char 1)) (defun sftran3-exit () "Insert EXIT statement. Invoked by \\\\[sftran3-exit]." (interactive) (sftran3-statement "EXIT ")) (defun sftran3-external () "Insert EXTERNAL declaration. Invoked by \\\\[sftran3-external]." (interactive) (sftran3-declaration "EXTERNAL")) (defun sftran3-format () "Insert FORMAT declaration. Invoked by \\\\[sftran3-format]." (interactive) (sftran3-kill-indentation) (sftran3-statement "FORMAT ()") (search-backward ")")) (defun sftran3-forward-token (&optional arg) "Move forward over ARG tokens (scalars, or array or function references." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (re-search-forward sftran3-token-regexp nil t arg)) (defun sftran3-function-abbrev () "Prompt for a function type, then invoke sftran3-function to insert a FUNCTION () ... END PROGRAM statement block. This function is called during word abbreviation expansion." (let ((function-type)) (setq function-type (completing-read "Function type: " sftran3-standard-types nil nil nil)) (sftran3-function function-type))) (defun sftran3-function-menu (&optional function-type) "Prompt for a function type, then invoke sftran3-function to insert a FUNCTION () ... END PROGRAM statement block. This function is called in response to a menu selection." (interactive (list (completing-read "Function type: " sftran3-standard-types nil nil nil))) (sftran3-function function-type)) (defun sftran3-function (function-type) "Insert FUNCTION () ... END PROGRAM statement block. Invoked by \\\\[sftran3-function]." (interactive (list (completing-read "Function type: " sftran3-standard-types nil nil nil))) (setq sftran3-comment-prefix sftran3-default-comment-prefix) (sftran3-kill-indentation) (let ((function-name)) (setq function-name (read-string "Function name: ")) (sftran3-statement (concat function-type " FUNCTION " function-name " ()\n"))) (insert sftran3-default-comment-prefix "()\n") (insert sftran3-default-comment-prefix) (sftran3-date-edit) (insert "INLINE(" sftran3-inline-comment ")\n") (sftran3-statement "RETURN\n") (sftran3-statement "END PROGRAM\n") (search-backward "()\n" nil nil 2) (forward-char 1)) (defun sftran3-gripe () "Send mail to maintainer of sftran3-mode with comments, gripes, and bug reports. Invoked by \\\\[sftran3-gripe]." (interactive) (mail-other-window) (beginning-of-line) (if (not (looking-at "^To: $")) (progn (princ "Trash in *mail* buffer--please clear it and try again") (goto-char (point-min)) (ding)) (progn (end-of-line) (insert sftran3-author-email-address) (end-of-line 2) (insert "sftran3-mode gripe report {" sftran3-mode-version "}") (goto-char (point-max))))) (defun sftran3-hollerith (&optional arg) "Prompt for and read a character string, then insert it as a Hollerith string at point. With an argument, also insert the string length as a following integer value. Invoked by \\\\[sftran3-hollerith]." (interactive) (let ((the-string)) (setq the-string (read-string "Hollerith string: ")) (insert (format "%dH%s" (length the-string) the-string)) (if (or (not (null arg)) (not (null current-prefix-arg))) (insert (format ",%d" (length the-string)))))) (defun sftran3-if () "Insert IF () statement. Invoked by \\\\[sftran3-if]." (interactive) (sftran3-statement "IF () ") (search-backward ")")) (defun sftran3-if-then () "Insert IF () THEN ... ELSE ... END IF statement. Invoked by \\\\[sftran3-if-then]." (interactive) (sftran3-statement "IF () THEN") (sftran3-statement "ELSE") (sftran3-statement "END IF") (delete-blank-lines) (search-backward "THEN") (end-of-line) (newline) (sftran3-next-level) (search-backward ")")) (defun sftran3-implicit () "Insert IMPLICIT declaration. Invoked by \\\\[sftran3-implicit]." (interactive) (let ((data-type)) (setq data-type (completing-read "Data type: " sftran3-standard-types nil nil nil)) (sftran3-declaration (concat "IMPLICIT " data-type " ( )"))) (search-backward " )")) (defun sftran3-include () "Insert INCLUDE directive. Invoked by \\\\[sftran3-include]." (interactive) (sftran3-directive "INCLUDE ()\n") (search-backward ")")) (defun sftran3-indent () "Insert INDENT directive. Invoked by \\\\[sftran3-indent]." (interactive) (sftran3-directive "INDENT()\n") (search-backward ")")) (defun sftran3-indent-line () "Indent the current line to the current indentation level. If point is already at that level, indent one more level." (interactive) (sftran3-back-to-indentation) (delete-horizontal-space) (insert (sftran3-blanks (- sftran3-column-indentation (current-column))))) (defun sftran3-indent-new-comment-line () "Continue the current comment on a new line with the same indentation." (interactive "*") (beginning-of-line) (let ((start (point)) (end)) (end-of-line) (setq end (point)) (goto-char start) (if (not (search-forward " " end t)) (goto-char end) (re-search-forward "[^ ]") (backward-char 1)) (setq sftran3-comment-prefix (buffer-substring start (point))) (end-of-line) (newline) (insert sftran3-comment-prefix))) (defun sftran3-inline () "Insert INLINE directive. Invoked by \\\\[sftran3-inline]." (interactive) (sftran3-directive (concat "INLINE(" sftran3-inline-comment ")\n")) (search-backward sftran3-inline-comment)) (defun sftran3-inquire (&optional arg) "Insert INQUIRE statement in either the short form (no argument), or the long form (with an argument)." (interactive) (if (or (not (null arg)) (not (null current-prefix-arg))) (sftran3-inquire-long) ;then had argument (sftran3-inquire-short))) ;else no argument (defun sftran3-inquire-long () "Insert INQUIRE statement (long form), with all possible keywords. Each corresponding value should be a variable of the indicated data type. Invoked by \\\\[sftran3-inquire-long]." (interactive) (let ((sep (concat ",\n" sftran3-continuation-prefix (sftran3-blanks (+ 3 sftran3-column-indentation))))) (sftran3-statement (concat "INQUIRE (UNIT = " sep "FILE = ''" sep "ACCESS = charvar" sep "BLANK = charvar" sep "DIRECT = charvar" sep "ERR = label" sep "EXIST = logvar" sep "FORM = charvar" sep "FORMATTED = charvar" sep "IOSTAT = intvar" sep "NAME = charvar" sep "NAMED = logvar" sep "NEXTREC = intvar" sep "NUMBER = intvar" sep "OPENED = logvar" sep "RECL = intvar" sep "SEQUENTIAL = charvar" sep "UNFORMATTED = charvar)"))) (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-inquire-short () "Insert INQUIRE statement (short form) with commonly-used keywords. Each corresponding value should be a variable of the indicated data type. Invoked by \\\\[sftran3-inquire-short]." (interactive) (let ((sep (concat ",\n" sftran3-continuation-prefix (sftran3-blanks (+ 3 sftran3-column-indentation))))) (sftran3-statement (concat "INQUIRE (UNIT = " sep "FILE = ''" sep "EXIST = logvar" sep "OPENED = logvar)"))) (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-insert-block (initial final re-position-after) "INTERNAL: Insert an SFTRAN3 statement block at the current indentation. INITIAL is the first statement, FINAL is the last statement, and RE-POSITION-AFTER is a string to re-search backwards for, leaving point at the end of the match before returning. A newline is automatically supplied after FINAL." (sftran3-statement initial) (sftran3-statement (sftran3-blanks sftran3-level-indentation)) (insert "\n") (sftran3-statement final) (delete-blank-lines) (re-search-backward re-position-after) (forward-line 1) (sftran3-next-level) (re-search-backward re-position-after) (goto-char (match-end 0))) (defun sftran3-integer () "Insert INTEGER declaration. Invoked by \\\\[sftran3-integer]." (interactive) (sftran3-declaration "INTEGER")) (defun sftran3-intrinsic () "Insert INTRINSIC declaration. Invoked by \\\\[sftran3-intrinsic]." (interactive) (sftran3-declaration "INTRINSIC")) (defun sftran3-justify-statement-label () "If the current line is not at least 6 characters long, supply blank padding to that length. Then right-adjust the numeric statement label, if any, in columns 1..5, leaving point at column 7." (interactive) (end-of-line) ;; if the line is too short, blank pad through column 6 (if (< (current-column) 6) (insert (sftran3-blanks (- 6 (current-column))))) (beginning-of-line) (cond ((and (looking-at sftran3-statement-label-regexp) (not (looking-at " "))) (while (looking-at "^.... ") (insert " ") (forward-char 4) (delete-char 1) (beginning-of-line)))) (end-of-line) (cond ((< 6 (current-column)) (beginning-of-line) (forward-char 6)))) (defun sftran3-kill-indentation () "INTERNAL: Reset indentation back to column 6." (setq sftran3-column-indentation 6) (setq fill-prefix sftran3-continuation-prefix)) (defun sftran3-label () "Prompt for an SFTRAN3 label and insert it at the correct column offset." (interactive) (let ((label)) (setq label (read-string "Label: ")) (sftran3-begin-newline) (insert " " label ":"))) (defun sftran3-lineup () "Insert LINEUP directive. Invoked by \\\\[sftran3-lineup]." (interactive) (sftran3-directive "LINEUP()\n") (search-backward ")")) (defun sftran3-logical () "Insert LOGICAL declaration. Invoked by \\\\[sftran3-logical]." (interactive) (sftran3-declaration "LOGICAL")) (defun sftran3-mode () "Set up for SFTRAN3 editing. The SFTRAN3 language is a superset of Fortran 77, providing powerful control structures. In the case of control constructs, indentation is automatically adjusted so that a linefeed will move to the correct level inside the construct. Please report bugs, comments, and enhancements by e-mail to beebe@math.utah.edu (Internet) sftran3-gripe (on \\\\[sftran3-gripe]) makes this easier. All functions in this mode have key bindings: \\{sftran3-mode-map} " (interactive) (setq indent-tabs-mode nil) ;tabs are BAD news in SFTRAN3/Fortran (setq major-mode 'sftran3-mode) ;; (setq mode-name (concat "sftran3 {" sftran3-mode-version "}")) (setq mode-name (concat "sftran3")) (sftran3-version) (make-local-variable 'indent-line-function) (setq indent-line-function 'sftran3-indent-line) (setq case-fold-search t) ;Fortran/SFTRAN3 are case-insensitive (sftran3-default-abbrev-table) (setq local-abbrev-table sftran3-mode-abbrev-table) (sftran3-default-keymap) (use-local-map sftran3-mode-map) (make-local-variable 'comment-start) (setq comment-start (concat sftran3-inline-comment " ")) (make-local-variable 'comment-start-skip) (setq comment-start-skip (concat sftran3-inline-comment "[ ]*")) (make-local-variable 'comment-end) (setq comment-end "") (make-local-variable 'comment-column) (setq comment-column 32) (sftran3-x-window-setup) (run-hooks 'sftran3-mode-hook)) (fset 'sf3-mode 'sftran3-mode) ; provide an alternate name for this (defun sftran3-namelist () "Insert NAMELIST declaration. Invoked by \\\\[sftran3-namelist]." (interactive) (sftran3-declaration "NAMELIST / /") (search-backward "/")) (defun sftran3-newline-and-indent () "If point is on an sftran3 structure END statement or a Fortran CONTINUE statement, reset sftran3-column-indentation to match its indentation. Start a new line following the current line and indent it according to the value of the current sftran3-column-indentation. Invoked by \\\\[sftran3-newline-and-indent]." (interactive) (beginning-of-line) (if (or (looking-at "^ *END *[A-Z]+") (looking-at "^[0-9 ]+continue")) (progn (beginning-of-line) (sftran3-skip-label) (re-search-forward "[^ ]") (backward-char 1) (sftran3-set-fill-prefix))) (end-of-line) (newline-and-indent)) (defun sftran3-news () "View the sftran3.el file to see its revision history which documents changes in reverse chronological order. Invoked by \\\\[sftran3-news]." (interactive) (let ((the-file)) (catch 'DONE (mapcar (function (lambda (the-path) (setq the-file (concat the-path (if (string-equal (system-name) "vax-vms") "" "/") "sftran3.el")) (if (file-exists-p the-file) (progn (view-file the-file) (throw 'DONE nil))))) load-path)))) (defun sftran3-next-case () "Insert CASE nnn statement for next case, leaving indentation level unchanged." (setq sftran3-case-number (1+ sftran3-case-number)) (sftran3-statement (format "CASE %d" sftran3-case-number))) (defun sftran3-next-level (&optional arg) "Increase the statement indentation by ARG (default 1) levels. \ Invoked by \\\\[sftran3-next-level]." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (sftran3-previous-level (- arg))) (defun sftran3-noindent () "Insert NOINDENT directive. Invoked by \\\\[sftran3-noindent]." (interactive) (sftran3-directive "NOINDENT\n")) (defun sftran3-open (&optional arg) "Insert OPEN statement in either the short form (no argument), or the long form (with an argument)." (interactive) (if (or (not (null arg)) (not (null current-prefix-arg))) (sftran3-open-long) ;then had argument (sftran3-open-short))) ;else no argument (defun sftran3-open-long () "Insert OPEN statement. The default attributes are sequential formatted unknown, since these are the ones most commonly required. Invoked by \\\\[sftran3-open-long]." (interactive) (let ((sep (concat ",\n" sftran3-continuation-prefix (sftran3-blanks sftran3-column-indentation)))) (sftran3-statement (concat "OPEN (UNIT = " sep "FILE = ''" sep "ACCESS = 'sequential'" sep "BLANK = ''" sep "ERR = " sep "FORM = 'formatted'" sep "IOSTAT = " sep "RECL = " sep "STATUS = 'unknown')"))) (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-open-short () "Insert OPEN statement. The default attributes are sequential formatted unknown, since these are the ones most commonly required. Invoked by \\\\[sftran3-open-short]." (interactive) (let ((sep (concat ",\n" sftran3-continuation-prefix (sftran3-blanks sftran3-column-indentation)))) (sftran3-statement (concat "OPEN (UNIT = " sep "ACCESS = 'sequential'" sep "FILE = ''" sep "FORM = 'formatted'" sep "STATUS = 'unknown')"))) (search-backward "UNIT = ") (search-forward "= ")) (defun sftran3-open-line (arg) "Insert a newline and leave point before it. With ARG, inserts that many newlines." ;; definition borrowed from emacs version 18 open-line in simple.el ;; version 19 open-line does not work the way we want here (interactive "*p") (let ((flag (and (bolp) (not (bobp))))) (if flag (forward-char -1)) (while (> arg 0) (insert ?\n) (goto-char (1- (point))) (setq arg (1- arg))) (if flag (forward-char 1)))) (defun sftran3-paginate-routines () "Insert page marks at beginning of marked region of buffer and after each END PROGRAM statement. Invoked by \\\\[sftran3-paginate-routines]." (interactive) (mark-whole-buffer) (while (re-search-forward sftran3-routine-regexp nil t) (let ((start (point)) (routine nil)) (forward-word 1) (setq routine (buffer-substring start (point))) (beginning-of-line 1) (insert "\f\n") (forward-line 1))) (goto-char (point-min))) (defun sftran3-paginate-procedures () "Insert page marks at beginning of each PROCEDURE statement. Invoked by \\\\[sftran3-paginate-procedures]." (interactive) (mark-whole-buffer) (while (re-search-forward sftran3-procedure-regexp nil t) (beginning-of-line 1) (insert "\f\n") (forward-line 1)) (goto-char (point-min))) (defun sftran3-pause () "Insert PAUSE statement. Invoked by \\\\[sftran3-pause]." (interactive) (sftran3-statement "PAUSE ")) (defun sftran3-parameter () "Insert PARAMETER declaration. Invoked by \\\\[sftran3-parameter]." (interactive) (sftran3-declaration "PARAMETER") (insert "( = )") (search-backward " =")) (defun sftran3-prepare-abbrev-list-buffer () (save-excursion (set-buffer (get-buffer-create "*Abbrevs*")) (erase-buffer) (insert-abbrev-table-description 'sftran3-mode-abbrev-table t) (goto-char (point-min)) (set-buffer-modified-p nil) (edit-abbrevs-mode)) (get-buffer-create "*Abbrevs*")) (defun sftran3-previous-level (&optional arg) "Reduce the statement indentation by ARG (default 1) levels. \ Invoked by \\\\[sftran3-previous-level]." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (setq sftran3-column-indentation (min 60 (max 6 (- sftran3-column-indentation (* arg sftran3-level-indentation))))) (message (format "sftran3-column-indentation: %d" sftran3-column-indentation)) (delete-horizontal-space) (insert (sftran3-blanks (- 7 (current-column)))) (beginning-of-line) (sftran3-indent-line)) (defun sftran3-print () "Insert PRINT statement. Invoked by \\\\[sftran3-print]." (interactive) (sftran3-statement "PRINT *, ")) (defun sftran3-procedure () "Insert PROCEDURE () ... END PROCEDURE Statement. Invoked by \\\\[sftran3-procedure]." (interactive) (sftran3-begin-newline) (sftran3-kill-indentation) (insert sftran3-comment-prefix) (delete-horizontal-space) (insert "\n") (sftran3-insert-block "PROCEDURE ()" "END PROCEDURE" "(")) (defun sftran3-program () "Insert PROGRAM statement. Invoked by \\\\[sftran3-program]." (interactive) (setq sftran3-comment-prefix sftran3-default-comment-prefix) (sftran3-kill-indentation) (sftran3-statement "PROGRAM ")) (defun sftran3-read () "Insert READ statement. Invoked by \\\\[sftran3-read]." (interactive) (sftran3-statement "READ ()") (search-backward ")")) (defun sftran3-real () "Insert REAL declaration. Invoked by \\\\[sftran3-real]." (interactive) (sftran3-declaration "REAL")) (defun sftran3-return () "Insert RETURN statement. Invoked by \\\\[sftran3-return]." (interactive) (sftran3-statement "RETURN\n")) (defun sftran3-rewind () "Insert REWIND statement. Invoked by \\\\[sftran3-rewind]." (interactive) (sftran3-statement "REWIND ")) (defun sftran3-save () "Insert SAVE declaration. Invoked by \\\\[sftran3-save]." (interactive) (sftran3-declaration "SAVE")) (defun sftran3-set-fill-prefix () "Set the fill prefix and statement indentation to the current line up to point. Both comment lines and non-comment lines are handled. Filling expects lines to start with the fill prefix and reinserts the fill prefix in each resulting line. If the line is a comment line, the fill prefix is reset to match. \ Invoked by \\\\[sftran3-set-fill-prefix]." (interactive) (let ((fill-point (point))) (beginning-of-line) (if (looking-at sftran3-comment-start-regexp) (progn (setq sftran3-comment-prefix (buffer-substring (point) fill-point)) (goto-char fill-point) (set-fill-prefix) (princ (concat "fill-prefix: \"" fill-prefix "\""))) (goto-char fill-point) (setq sftran3-column-indentation (min 60 (max 6 (current-column)))) (setq fill-prefix (concat sftran3-continuation-prefix (sftran3-blanks (+ sftran3-level-indentation (- sftran3-column-indentation 6))))) (princ (format "sftran3-column-indentation = %d" sftran3-column-indentation))))) (defun sftran3-skip-label () "INTERNAL: Skip over any structure label, statement label, or comment prefix on the current line. In a comment statement, position to the current indentation level." (let ((cp (point))) (beginning-of-line) (cond ;; if we have a comment line, remove or add blanks to ;; position at the current indentation column ((looking-at sftran3-comment-start-regexp) (end-of-line) (cond ((> (current-column) sftran3-column-indentation) (beginning-of-line) (forward-char sftran3-column-indentation)) ((< (current-column) sftran3-column-indentation) (insert (sftran3-blanks (- sftran3-column-indentation (current-column))))))) ;; if we have a structure label, move past its trailing colon ((looking-at sftran3-structure-label-regexp) (search-forward ":")) ;; if we have a Fortran statement label, move to column 7 ((looking-at sftran3-statement-label-regexp) (sftran3-justify-statement-label)) ;; otherwise just stay where we were (t (goto-char cp))))) (defun sftran3-sort-procedures () "Sort procedures in the current routine into alphabetical order. Invoked by \\\\[sftran3-sort-procedures]." (interactive) (mark-whole-buffer) (save-excursion (re-search-forward sftran3-procedure-regexp) (beginning-of-line 1) (let ((proc-start (point))) (re-search-forward sftran3-end-routine-regexp) (beginning-of-line) (narrow-to-region proc-start (point)) (goto-char proc-start) (while (re-search-forward sftran3-procedure-regexp nil t) (let ((start (point)) (procname nil)) (end-of-line 1) (setq procname (buffer-substring start (point))) (beginning-of-line 1) (insert "\f" sftran3-sort-prefix procname "\n") ;set sort tag (forward-line 1))) (mark-whole-buffer) (sort-pages nil (point-min) (point-max)) (mark-whole-buffer) (flush-lines (concat "^[\f]+$\\|" sftran3-sort-prefix)) ;remove sort tags (goto-char (point-min))))) (defun sftran3-sort-routines () "Sort subroutines and functions in the buffer into alphabetical order. Invoked by \\\\[sftran3-sort-routines]." (interactive) (mark-whole-buffer) (while (re-search-forward sftran3-routine-regexp nil t) (let ((start (point)) (routine nil)) (forward-word 1) (setq routine (buffer-substring start (point))) (beginning-of-line 1) (insert "\f" sftran3-sort-prefix routine "\n") ;set sort tag (forward-line 1))) (mark-whole-buffer) (sort-pages nil (point-min) (point-max)) (mark-whole-buffer) (flush-lines (concat "^\f$\\|" sftran3-sort-prefix)) ;remove sort tags (goto-char (point-min))) (defun sftran3-sort-tokens () "Sort Fortran or SFTRAN3 tokens (words) between point and mark. These are separated by commas outside parentheses; that is, an array or function reference is a complete token. Invoked by \\\\[sftran3-sort-tokens]." (interactive) (save-restriction (narrow-to-region (mark) (point)) (sort-regexp-fields nil sftran3-token-regexp "\\&" (point-min) (point-max)) (goto-char (point-min)) (widen))) (defun sftran3-statement (statement) "INTERNAL: Insert STATEMENT on a new line after point, supplying any required leading indentation. Point is left at the end of the inserted line. If sftran3-lowercase-keywords is non-nil, the insertion is converted to lowercase." (sftran3-begin-newline) (insert (sftran3-blanks sftran3-column-indentation)) (let ((start (point))) (insert statement) (if sftran3-lowercase-keywords (downcase-region start (point))))) (defun sftran3-stet () "Insert STET directive. Invoked by \\\\[sftran3-stet]." (interactive) (sftran3-directive "STET()\n") (search-backward ")")) (defun sftran3-stop () "Insert STOP statement. Invoked by \\\\[sftran3-stop]." (interactive) (sftran3-statement "STOP\n")) (defun sftran3-subroutine () "Insert SUBROUTINE () ... END PROGRAM statement block. Invoked by \\\\[sftran3-subroutine]." (interactive) (setq sftran3-comment-prefix sftran3-default-comment-prefix) (sftran3-kill-indentation) (sftran3-statement "SUBROUTINE ()\n") (insert sftran3-default-comment-prefix "()\n") (insert sftran3-default-comment-prefix) (sftran3-date-edit) (insert "INLINE(" sftran3-inline-comment ")\n") (sftran3-statement "RETURN\n") (sftran3-statement "END PROGRAM\n") (search-backward "SUBROUTINE ()") (forward-char 12)) (defun sftran3-tab (&optional arg) "Indent current statement to current sftran3-column-indentation. If statement is already at that indentation level, indent one more level. If the line begins with a statement label, the label will be right justified. With a numeric argument, the indentation is increased or decreased that many levels. Invoked by \\\\[sftran3-tab]." (interactive) ;; get number of indentation levels to change (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 0))) ;else provide default ;; reset the indentation level (setq sftran3-column-indentation (min 60 (max 6 (+ sftran3-column-indentation (* arg sftran3-level-indentation))))) (let ((initial-indentation (current-column))) (sftran3-justify-statement-label) ;; position to the first non-blank after any label or comment start (sftran3-back-to-indentation) ;; insert or remove indentation spaces, as necessary (cond ;; if we are indented too far, discard indentation spaces, and ;; reinsert new ones to get to the correct level ((> (current-column) sftran3-column-indentation) (delete-horizontal-space) (insert (sftran3-blanks (- sftran3-column-indentation (current-column))))) ;; if we are not indented enought, insert extra spaces ((< (current-column) sftran3-column-indentation) (insert (sftran3-blanks (- sftran3-column-indentation (current-column)))))) ;; if we haven't moved from the original indentation, then ;; increase the indentation level by one, as long as the ;; argument is non-negative (cond ((and (>= arg 0) (= initial-indentation sftran3-column-indentation)) (setq sftran3-column-indentation (min 60 (max 6 (+ sftran3-column-indentation sftran3-level-indentation)))) (insert (sftran3-blanks (- sftran3-column-indentation (current-column)))))))) (defun sftran3-token-add (&optional arg) "With point after a Fortran token, say foo(bar), generate an assignment that increments the token by ARG." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (if (< arg 0) (sftran3-token-operator " - " (format "%d" (- arg))) (sftran3-token-operator " + " (format "%d" arg)))) (defun sftran3-token-divide (&optional arg) "With point after a Fortran token, say foo(bar), generate an assignment that divides the token by ARG." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (if (< arg 0) (sftran3-token-operator " / " (format "(%d)" arg)) (sftran3-token-operator " / " (format "%d" arg)))) (defun sftran3-token-multiply (&optional arg) "With point after a Fortran token, say foo(bar), generate an assignment that multiplies the token by ARG." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (if (< arg 0) (sftran3-token-operator " * " (format "(%d)" arg)) (sftran3-token-operator " * " (format "%d" arg)))) (defun sftran3-token-subtract (&optional arg) "With point after a Fortran token, say foo(bar), generate an assignment that decrements the token by ARG." (interactive) (cond ((not (null arg))) ;do nothing if explicit arg ((not (null current-prefix-arg)) ;else use prefix arg (setq arg (prefix-numeric-value current-prefix-arg))) (t (setq arg 1))) ;else provide default (if (< arg 0) (sftran3-token-operator " + " (format "%d" (- arg))) (sftran3-token-operator " - " (format "%d" arg)))) (defun sftran3-token-operator (operator value) "INTERNAL: With point after a Fortran token, say foo(bar), generate an assignment that looks like foo(bar) = foo(bar) " (let ((start) (token)) (sftran3-backward-token 1) (search-backward " ") (forward-char 1) (setq start (point)) (sftran3-forward-token 1) (setq token (buffer-substring start (point))) (insert " = " token) (insert operator value))) (defun sftran3-unpaginate () "Remove page marks in buffer. Invoked by \\\\[sftran3-unpaginate]." (interactive) (mark-whole-buffer) (flush-lines "^\f$") (goto-char (point-min))) (defun sftran3-version () "Show the version number and date of sftran3-mode." (interactive) (message "sftran3 mode version %s" sftran3-mode-version)) (defun sftran3-write () "Insert WRITE statement. Invoked by \\\\[sftran3-write]." (interactive) (sftran3-statement "WRITE ()") (search-backward ")")) ;; This code must come last, since it refers to functions defined above. (defun sftran3-x-window-setup () "When a window system is available, provide pop-up menus attached to a mouse button (emacs 18 or earlier), or to the top-of-screen menu bar (emacs 19 or later). Otherwise, do nothing at all." (interactive) (if (and (not (boundp 'epoch::version)) (boundp 'window-system) window-system) (if (string-lessp (substring emacs-version 0 2) "19") (progn ;emacs 18 or earlier (load "sf3-menu" t t nil) (sftran3-x-environment) (message "Popup menus bound to Control-left-mouse-button")) (progn ;emacs 19 or later ;; We add three menu bar items: sf3-stmt, sf3-decl, and sf3-misc. ;; These are placed in sftran3-mode-map so that they take effect only ;; in sftran3-mode. They must be declared in reverse order since ;; `define-key' puts new bindings at the front. (define-key sftran3-mode-map [menu-bar sf3-misc] (cons "sf3-misc" sftran3-menu-bar-misc-menu)) (define-key sftran3-menu-bar-misc-menu [stet] '("stet" . sftran3-stet)) (define-key sftran3-menu-bar-misc-menu [noindent] '("noindent" . sftran3-noindent)) (define-key sftran3-menu-bar-misc-menu [lineup] '("lineup" . sftran3-lineup)) (define-key sftran3-menu-bar-misc-menu [inline] '("inline" . sftran3-inline)) (define-key sftran3-menu-bar-misc-menu [indent] '("indent" . sftran3-indent)) (define-key sftran3-menu-bar-misc-menu [include] '("include" . sftran3-include)) (define-key sftran3-menu-bar-misc-menu [version] '("version" . sftran3-version)) (define-key sftran3-menu-bar-misc-menu [unpaginate] '("unpaginate" . sftran3-unpaginate)) (define-key sftran3-menu-bar-misc-menu [sort-tokens] '("sort tokens" . sftran3-sort-tokens)) (define-key sftran3-menu-bar-misc-menu [sort-routines] '("sort routines" . sftran3-sort-routines)) (define-key sftran3-menu-bar-misc-menu [sort-procedures] '("sort procedures" . sftran3-sort-procedures)) (define-key sftran3-menu-bar-misc-menu [paginate-procedures] '("paginate procedures" . sftran3-paginate-procedures)) (define-key sftran3-menu-bar-misc-menu [hollerith] '("hollerith" . sftran3-hollerith)) (define-key sftran3-menu-bar-misc-menu [gripe] '("gripe" . sftran3-gripe)) (define-key sftran3-menu-bar-misc-menu [date-edit] '("date-edit" . sftran3-date-edit)) (define-key sftran3-menu-bar-misc-menu [date] '("date" . sftran3-date)) (define-key sftran3-menu-bar-misc-menu [convert-comments] '("convert-comments" . sftran3-convert-comments)) (define-key sftran3-mode-map [menu-bar sf3-decl] (cons "sf3-decl" sftran3-menu-bar-decl-menu)) (define-key sftran3-menu-bar-decl-menu [save] '("save" . sftran3-save)) (define-key sftran3-menu-bar-decl-menu [parameter] '("parameter" . sftran3-parameter)) (define-key sftran3-menu-bar-decl-menu [namelist] '("namelist" . sftran3-namelist)) (define-key sftran3-menu-bar-decl-menu [intrinsic] '("intrinsic" . sftran3-intrinsic)) (define-key sftran3-menu-bar-decl-menu [external] '("external" . sftran3-external)) (define-key sftran3-menu-bar-decl-menu [equivalence] '("equivalence" . sftran3-equivalence)) (define-key sftran3-menu-bar-decl-menu [data] '("data" . sftran3-data)) (define-key sftran3-menu-bar-decl-menu [common] '("common" . sftran3-common)) (define-key sftran3-menu-bar-decl-menu [real] '("real" . sftran3-real)) (define-key sftran3-menu-bar-decl-menu [logical] '("logical" . sftran3-logical)) (define-key sftran3-menu-bar-decl-menu [integer] '("integer" . sftran3-integer)) (define-key sftran3-menu-bar-decl-menu [double-precision] '("double precision" . sftran3-double-precision)) (define-key sftran3-menu-bar-decl-menu [complex] '("complex" . sftran3-complex)) (define-key sftran3-menu-bar-decl-menu [character] '("character" . sftran3-character)) (define-key sftran3-mode-map [menu-bar sf3-stmt] (cons "sf3-stmt" sftran3-menu-bar-stmt-menu)) (define-key sftran3-menu-bar-stmt-menu [write] '("write" . sftran3-write)) (define-key sftran3-menu-bar-stmt-menu [subroutine] '("subroutine" . sftran3-subroutine)) (define-key sftran3-menu-bar-stmt-menu [stop] '("stop" . sftran3-stop)) (define-key sftran3-menu-bar-stmt-menu [rewind] '("rewind" . sftran3-rewind)) (define-key sftran3-menu-bar-stmt-menu [return] '("return" . sftran3-return)) (define-key sftran3-menu-bar-stmt-menu [read] '("read" . sftran3-read)) (define-key sftran3-menu-bar-stmt-menu [program] '("program" . sftran3-program)) (define-key sftran3-menu-bar-stmt-menu [procedure] '("procedure" . sftran3-procedure)) (define-key sftran3-menu-bar-stmt-menu [print] '("print" . sftran3-print)) (define-key sftran3-menu-bar-stmt-menu [pause] '("pause" . sftran3-pause)) (define-key sftran3-menu-bar-stmt-menu [open-short] '("open (short)" . sftran3-open-short)) (define-key sftran3-menu-bar-stmt-menu [open-long] '("open (long)" . sftran3-open-long)) (define-key sftran3-menu-bar-stmt-menu [inquire-short] '("inquire (short)" . sftran3-inquire-short)) (define-key sftran3-menu-bar-stmt-menu [inquire-long] '("inquire (long)" . sftran3-inquire-long)) (define-key sftran3-menu-bar-stmt-menu [if] '("if ()" . sftran3-if)) (define-key sftran3-menu-bar-stmt-menu [if-then] '("if () then" . sftran3-if-then)) (define-key sftran3-menu-bar-stmt-menu [function] '("function" . sftran3-function-menu)) (define-key sftran3-menu-bar-stmt-menu [format] '("format" . sftran3-format)) (define-key sftran3-menu-bar-stmt-menu [exit] '("exit" . sftran3-exit)) (define-key sftran3-menu-bar-stmt-menu [end-if] '("end if" . sftran3-end-if)) (define-key sftran3-menu-bar-stmt-menu [end-file] '("end file" . sftran3-end-file)) (define-key sftran3-menu-bar-stmt-menu [else-if-then] '("else if () then" . sftran3-else-if-then)) (define-key sftran3-menu-bar-stmt-menu [else] '("else" . sftran3-else)) (define-key sftran3-menu-bar-stmt-menu [do-while] '("do while" . sftran3-do-while)) (define-key sftran3-menu-bar-stmt-menu [do-until] '("do until" . sftran3-do-until)) (define-key sftran3-menu-bar-stmt-menu [do-procedure] '("do (procedure)" . sftran3-do-procedure)) (define-key sftran3-menu-bar-stmt-menu [do-forever] '("do forever" . sftran3-do-forever)) (define-key sftran3-menu-bar-stmt-menu [do-for] '("do for" . sftran3-do-for)) (define-key sftran3-menu-bar-stmt-menu [do-case] '("do case" . sftran3-do-case)) (define-key sftran3-menu-bar-stmt-menu [do-block] '("do block" . sftran3-do-block)) (define-key sftran3-menu-bar-stmt-menu [cycle] '("cycle" . sftran3-cycle)) (define-key sftran3-menu-bar-stmt-menu [close-short] '("close (short)" . sftran3-close-short)) (define-key sftran3-menu-bar-stmt-menu [close-long] '("close (long)" . sftran3-close-long)) (define-key sftran3-menu-bar-stmt-menu [case-renumber] '("case-renumber" . sftran3-case-renumber)) (define-key sftran3-menu-bar-stmt-menu [case-k] '("case-k" . sftran3-case-k)) (define-key sftran3-menu-bar-stmt-menu [block-data] '("block data" . sftran3-block-data)))))) ;;; sftran3.el ends here