[comp.emacs] Pascal mode for GNU Emacs

escott%deis.uci.edu@ICSG.UCI.EDU (Scott Menter) (11/27/86)

A friend of mine (Erik Fortune) wrote a pretty good Pascal mode for
Gosling Emacs.  If somebody wants to port it to GNU Lisp, I'll provide
it.  If I get any response, I'll get ahold of it and put it somewhere
you can ftp it from.  By the way, it's geared for "pc", so hopefully
that's what you needed.

+----------------------------------------------------------------------+
 Scott Menter  UCI ICS Computing Support Group  Univ of Calif at Irvine
               (714) 856 7552                 Irvine, California  92717

 Internet:  escott@ics.uci.edu              UUCP:  ucbvax!ucivax!escott
 Bitnet:    escott@ucicp6         CSNet: escott%ics.uci.edu@csnet-relay
+----------------------------------------------------------------------+

pjmbaker@watcgl.UUCP (03/30/87)

Here is a pascal mode that was sent to me awhile back after I made the
same request.  I have subsequently had a number of requests for it so
I decided to post it.  I did NOT write it.  I do not even *like*
Pascal but was required to use it for a graphics project at U. of
Waterloo.  I believe the GNU people are including something derived
from this in their current (or next?) release of GNU emacs.

				Happy Editting
Peter Baker, Computer Science Dept., University of Waterloo
USENET:  {ihnp4|allegra|utzoo|utcsri}!watmath!watcgl!pjmbaker
CSNET :  pjmbaker%watcgl@waterloo.csnet
BITNET :  pjmbaker@water.bitnet
arpa  :  pjmbaker%watcgl%waterloo.csnet@csnet-relay.arpa


---------------- cut here ----------------
; Pascal editing support package
; Author Mick Jordan for Modula-2
; amended Peter Robinson
; ported to GNU Michael Schmidt <michael@pbinfo.uucp>
; Modified by Tom Perrine <Perrin@LOGICON.ARPA> (TEP)
; analogue for pascal by Vincent Broman <broman@bugs.nosc.mil>

(setq auto-mode-alist (cons (cons "\\.p$" 'pascal-mode) auto-mode-alist))
(setq auto-mode-alist (cons (cons "\\.h$" 'pascal-mode) auto-mode-alist))

;;; Added by TEP
(defvar pascal-mode-syntax-table nil
  "Syntax table in use in Pascal-mode buffers.")

(if pascal-mode-syntax-table
    ()
  (let ((table (make-syntax-table)))
    (modify-syntax-entry ?\\ "." table)
    (modify-syntax-entry ?\{ "<" table)
    (modify-syntax-entry ?\} ">" table)
    (modify-syntax-entry ?\( "()1" table)
    (modify-syntax-entry ?\) ")(4" table)
    (modify-syntax-entry ?\[ "(]" table)
    (modify-syntax-entry ?\] ")[" table)
    (modify-syntax-entry ?* ". 23" 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)
    (modify-syntax-entry ?\$ "_" table)
    (modify-syntax-entry ?< "." table)
    (modify-syntax-entry ?> "." table)
    (modify-syntax-entry ?\' "\"" table)
    (modify-syntax-entry ?\" "\"" table)
    (setq pascal-mode-syntax-table table)))

;;; Added by TEP
(defvar pascal-mode-map nil
  "Keymap used in Pascal mode.")

(if pascal-mode-map ()
  (let ((map (make-sparse-keymap)))
    (define-key map "\C-i" 'pascal-tab)
    (define-key map "\C-m" 'pascal-newline)
    (define-key map "\C-cb" 'pascal-begin)
    (define-key map "\C-cc" 'pascal-case)
    (define-key map "\C-c\C-c" 'pascal-const)
    (define-key map "\C-ce" 'pascal-else)
    (define-key map "\C-cf" 'pascal-for)
    (define-key map "\C-c\C-f" 'pascal-function)
    (define-key map "\C-ch" 'pascal-header)
    (define-key map "\C-ci" 'pascal-if)
    (define-key map "\C-c\C-i" 'pascal-include)
    (define-key map "\C-c\C-p" 'pascal-procedure)
    (define-key map "\C-cp" 'pascal-program)
    (define-key map "\C-cr" 'pascal-repeat)
    (define-key map "\C-c\C-r" 'pascal-record)
    (define-key map "\C-c\C-t" 'pascal-type)
    (define-key map "\C-c\C-v" 'pascal-var)
    (define-key map "\C-cw" 'pascal-while)
    (define-key map "\C-c\C-w" 'pascal-with)
    (define-key map "\C-c*" 'pascal-star-display-comment)
    (define-key map "\C-c{" 'pascal-display-comment)
    (define-key map "\C-c}" 'pascal-inline-comment)
    (define-key map "\C-c(" 'pascal-paired-parens)
    (define-key map "\C-c[" 'pascal-paired-brackets)
    (define-key map "\C-ct" 'pascal-toggle)
    (define-key map "\C-cL" 'pascal-link)
    (define-key map "\C-cC" 'pascal-compile)
    (setq pascal-mode-map map)))

(defvar pascal-indent 4 "*This variable gives the indentation in Pascal-Mode")
  
(defun pascal-mode ()
"This is a mode intended to support program development in Pascal.
Most control constructs of Pascal can be created by typing
Control-C followed by the first character of the construct.

C-c p    program        C-c b    begin-end
C-c C-c  const          C-c c    case-do
C-c C-t  type           C-c t    toggle between .p-.h
C-c C-v  var            C-c {    enter matched braces
C-c C-r  record         C-c r    repeat-until
C-c C-w  with-do        C-c w    while-do
C-c C-i  #include       C-c i    if-then
C-c C-p  procedure      C-c e    else
C-c C-f  function       C-c f    for-do

\\{pascal-mode-map}

Variable pascal-indent controls the number of spaces for each indentation."
  (interactive)
  (kill-all-local-variables)
  (use-local-map pascal-mode-map)
  (setq major-mode 'pascal-mode)
  (setq mode-name "Pascal")
  (make-local-variable 'comment-column)
  (setq comment-column 41)
  (make-local-variable 'end-comment-column)
  (setq end-comment-column 72)
  (set-syntax-table pascal-mode-syntax-table)
  (make-local-variable 'paragraph-start)
  (setq paragraph-start (concat "^$\\|" page-delimiter))
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
;  (make-local-variable 'indent-line-function)
;  (setq indent-line-function 'c-indent-line)
  (make-local-variable 'require-final-newline)
  (setq require-final-newline t)
  (make-local-variable 'comment-start)
  (setq comment-start "{\n")
  (make-local-variable 'comment-end)
  (setq comment-end "\n}")
  (make-local-variable 'comment-column)
  (setq comment-column 41)
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "/\\*+ *")
  (make-local-variable 'comment-indent-hook)
  (setq comment-indent-hook 'c-comment-indent)
  (make-local-variable 'parse-sexp-ignore-comments)
  (setq parse-sexp-ignore-comments t)
  (run-hooks 'pascal-mode-hook))

(defun pascal-newline ()
  "Start new line and indent to current tab stop."
  (interactive)
  (setq cc (current-indentation))
  (newline)
  (indent-to cc)
  )

(defun pascal-tab ()
  "Indent to next tab stop."
  (interactive)
  (indent-to (* (1+ (/ (current-indentation) pascal-indent)) pascal-indent)))

(defun pascal-begin ()
  "Insert a BEGIN-END pair and indent for the line between."
  (interactive)
  (insert "BEGIN")
  (pascal-newline)
  (pascal-newline)
  (insert "END;")
  (let ((comment (read-string "comment about block: ")))
    (cond ((not (string-equal comment "")) (insert " {" comment "}"))))
  (end-of-line 0))

(defun pascal-case ()
  "Build skeleton CASE statment, prompting for the <expression>."
  (interactive)
  (insert "CASE ")
  (let ((selector (read-string "selector-expr: ")))
    (progn
      (insert selector " OF")
      (pascal-newline)
      (pascal-newline)
      (insert "END; {case " selector "}")))
  (end-of-line 0)
  (pascal-tab))

(defun pascal-else ()
  "Insert ELSE keyword and indent for next line."
  (interactive)
  (insert "ELSE")
  (pascal-newline)
  (pascal-tab))

(defun pascal-for ()
  "Build skeleton FOR loop statment, prompting for the loop parameters."
  (interactive)
  (insert "FOR ")
  (insert (read-string "init: ") " TO ")
  (insert (read-string "limit: ") " DO")
  (pascal-newline)
  (pascal-tab))

(defun pascal-header ()
  "Insert a comment block containing the module title, author, etc."
  (interactive)
  (insert "(*\n    Title: \t")
  (insert (read-string "Title: "))
  (insert "\n    Created:\t")
  (insert (current-time-string))
  (insert "\n    Author: \t")
  (insert (user-full-name))
  (insert (concat "\n\t\t<" (user-login-name) "@" (system-name) ">\n"))
  (insert "*)\n\n"))

(defun pascal-if ()
  "Insert skeleton IF statment, prompting for a boolean-expression."
  (interactive)
  (insert "IF ")
  (insert (read-string "condition: ") " THEN")
  (pascal-newline)
  (pascal-tab))

(defun pascal-program ()
  (interactive)
  (insert "PROGRAM ")
  (let ((name (read-string "program name: " )))
    (insert name " (input, output")
    (let ((arglist (read-string "other file vars: ")))
      (cond ((not (string-equal "" arglist)) (insert ", " arglist)))
      (insert ");"))
    (pascal-newline)
    (pascal-newline)
    (insert "BEGIN")
    (pascal-newline)
    (pascal-newline)
    (insert "END. {")
    (insert name)
    (insert "}")
    (end-of-line 0)
    (pascal-tab)))

(defun pascal-procedure ()
  (interactive)
  (insert "PROCEDURE ")
  (let ((name (read-string "name: " )))
    (insert name "(")
    (insert (read-string "argument list: ") ");")
    (pascal-newline)
    (pascal-newline)
    (pascal-tab)
    (insert "BEGIN")
    (pascal-newline)
    (pascal-newline)
    (insert "END; {")
    (insert name)
    (insert "}")
    (end-of-line 0)
    (pascal-tab)))

(defun pascal-function ()
  (interactive)
  (insert "FUNCTION ")
  (let ((name (read-string "name: " )))
    (insert name "(")
    (insert (read-string "argument list: ") "): ")
    (insert (read-string "result type: ") ";")
    (pascal-newline)
    (pascal-newline)
    (pascal-tab)
    (insert "BEGIN")
    (pascal-newline)
    (pascal-newline)
    (insert "END; {")
    (insert name)
    (insert "}")
    (end-of-line 0)
    (pascal-tab)))

(defun pascal-with ()
  (interactive)
  (insert "WITH ")
  (insert (read-string "idents: "))
  (insert " DO")
  (pascal-newline)
  (pascal-tab))

(defun pascal-record ()
  (interactive)
  (insert "RECORD")
  (pascal-newline)
  (pascal-newline)
  (insert "END;")
  (let ((comment (read-string "comment about record: ")))
    (cond ((not (string-equal comment "")) (insert " {" comment "}"))))
  (end-of-line 0)
  (pascal-tab))

(defun pascal-type ()
  (interactive)
  (insert "TYPE")
  (pascal-newline)
  (pascal-tab))

(defun pascal-const ()
  (interactive)
  (insert "CONST")
  (pascal-newline)
  (pascal-tab))

(defun pascal-repeat ()
  (interactive)
  (insert "REPEAT")
  (pascal-newline)
  (pascal-newline)
  (insert "UNTIL ")
  (insert (read-string "exit cond: ") ";")
  (end-of-line 0)
  (pascal-tab))

(defun pascal-var ()
  (interactive)
  (insert "VAR")
  (pascal-newline)
  (pascal-tab))

(defun pascal-while ()
  (interactive)
  (insert "WHILE ")
  (insert (read-string "entry cond: "))
  (insert " DO")
  (pascal-newline)
  (pascal-tab))

(defun pascal-include ()
  (interactive)
  (insert "\n#include \"")
  (insert (read-string "header file: "))
  (insert "\"")
  (pascal-newline)
  (pascal-newline))


(defun pascal-paired-parens ()
  (interactive)
  (insert "()")
  (backward-char))


(defun pascal-paired-brackets ()
  (interactive)
  (insert "[]")
  (backward-char))

(defun pascal-inline-comment ()
  (interactive)
  (insert "{}")
  (backward-char))

(defun pascal-display-comment ()
"puts comment delimiters around a blank line, making a display comment."
  (interactive)
  (insert "{\n\n}")
  (end-of-line 0))

(defun pascal-star-display-comment ()
"starts a UNIX-style display comment."
  (interactive)
  (insert "(*\n *\n *)")
  (end-of-line 0)
  (pascal-tab))

(defun pascal-compile ()
  (interactive)
  (setq modulename (buffer-name))
  (compile (concat "pc -c " modulename)))

(defun pascal-link ()
  (interactive)
  (compile "make"))

;UNUSED?
;(defun execute-monitor-command (command)
;  (let* ((shell shell-file-name)
;	 (csh (equal (file-name-nondirectory shell) "csh")))
;    (call-process shell nil t t "-cf" (concat "exec " command))))

(defun pascal-toggle ()
  "Toggle between .p and .h files for the module."
  (interactive)
  (cond ((string-equal (substring (buffer-name) -2) ".h")
	 (find-file-other-window
	   (concat (substring (buffer-name) 0 -2) ".p")))
	((string-equal (substring (buffer-name) -2) ".p")
	 (find-file-other-window
	   (concat (substring (buffer-name) 0 -2)  ".h")))))

bob%tut.cis.ohio-state.edu@osu-eddie.UUCP (Bob Sutterfield) (07/02/87)

In article <807@watcgl.UUCP> pjmbaker@watcgl.UUCP (Peter J M Baker) writes:
>Here is a pascal mode that was sent to me awhile back after I made
>the same request.
> ...
>I believe the GNU people are including something derived from this in
>their current (or next?) release of GNU emacs.
> ...
>Peter Baker, Computer Science Dept., University of Waterloo

Thanks, Peter, for posting that, and to the other authors for their
work on Pascal-mode.  It is about to be very useful to some of our
students.  I wonder why it hasn't made it into a GNU distribution yet,
as a standard major mode?

>; Pascal editing support package
>; Author Mick Jordan for Modula-2
>; amended Peter Robinson
>; ported to GNU Michael Schmidt <michael@pbinfo.uucp>
>; Modified by Tom Perrine <Perrin@LOGICON.ARPA> (TEP)
>; analogue for pascal by Vincent Broman <broman@bugs.nosc.mil>
> ...
>(defun pascal-begin ()
>  "Insert a BEGIN-END pair and indent for the line between."
>  (interactive)
>  (insert "BEGIN")
>  (pascal-newline)
>  (pascal-newline)
>  (insert "END;")
>  (let ((comment (read-string "comment about block: ")))
>    (cond ((not (string-equal comment "")) (insert " {" comment "}"))))
>  (end-of-line 0))

I would suggest that you change all the keywords to lower case.  pc
has a -L switch that "Maps upper case letters in keywords and
identifiers to lower case", but it would be more convenient for many
users to have the keywords in lower case already.

Perhaps this should be controlled by a variable, something like
`pascal-keywords-upper-case', so that it would be more individually
controllable.  The default should be to put the keywords in lower
case, since pc by default expects them that way.  When users want more
readable code, they can both turn on the variable, and start using the
-L switch.
-=-
 Bob Sutterfield, Department of Computer and Information Science
 The Ohio State University; 2036 Neil Ave. Columbus OH USA 43210-1277
 bob@ohio-state.{arpa,csnet} or ...!cbosgd!osu-eddie!bob
 soon: bob@aargh.cis.ohio-state.edu