[comp.emacs] Wanted: Pascal Minor mode for Gnu Emacs

lazlor@ucscb.UCSC.EDU (Allen) (10/06/88)

	I am looking for a Pascal Minor mode for Gnu Emacs. We are running
GNU Emacs 18.48.2 on an ISI Optimum V and 18.50.1 on a Vax 11/750.

Thanks in advance,
Allen Smith
--

==============================================================================
* lazlor@ucscb.UCSC.EDU - INTERNET    | 'The land divided, the world united' *
* ...ucbvax!ucscc!ucscb!lazlor - UUCP |  Any opinions, whether implied or    *
* lazlor%ucscb@ucscc.BITNET BITNET    |  expressed are not those of UCSC.    *
==============================================================================

bob@banjo.cis.ohio-state.edu (Bob Sutterfield) (10/07/88)

In article <LAZLOR.88Oct5210131@ucscb.UCSC.EDU> lazlor@ucscb.UCSC.EDU (Allen) writes:
>I am looking for a Pascal Minor mode for Gnu Emacs.

Here's the article that came to us lo these many moons ago, carrying a
pascal-mode.el that has been so helpful to so many of our students.
I've passed it on to a dozen or to similar inquirers since then.
Notwithstanding Mr Baker's comment, I don't know whether there are any
plans to include a Pascal mode with a standard distribution.	--Bob

Article 638 of comp.emacs:
Relay-Version: version B 2.10.3 alpha 5/22/85; site osu-eddie.UUCP
Path: osu-eddie!cbatt!ihnp4!ptsfa!lll-lcc!seismo!mnetor!utzoo!utgpu!water!watnot!watcgl!pjmbaker
From: pjmbaker@watcgl.UUCP
Newsgroups: comp.emacs
Subject: Re: Pascal mode for GNU emacs (here is one)
Message-ID: <807@watcgl.UUCP>
Date: 30 Mar 87 15:01:01 GMT
Date-Received: 4 Apr 87 07:35:30 GMT
References: <27@gt-eedsp.UUCP>
Reply-To: pjmbaker@watcgl.UUCP (Peter J M Baker)
Distribution: world
Organization: U. of Waterloo, Ontario
Lines: 389


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")))))


-=-
Zippy sez,								--Bob
OMNIVERSAL AWARENESS??  Oh, YEH!!  First you need 4 GALLONS of JELL-O
 and a BIG WRENCH!!...  I think you drop th'WRENCH in the JELL-O as if
 it was a FLAVOR, or an INGREDIENT...  ...or...I...um...  WHERE'S the
 WASHING MACHINES?

broman@schroeder.nosc.mil (Vincent Broman) (10/11/88)

Seeing the older pascal-mode float by reminded me that I use a significantly
rewritten descendent version now, with more features and some support for
Berkeley pc and DOMAIN Pascal compiler idiosyncracies.  The implementation
of pascal-indent-line is unfinished and unused.

If FSF wants to pick this up, fine with me.

Vincent Broman,  code 632, Naval Ocean Systems Center, San Diego, CA 92152, USA
Phone: +1 619 553 1641    Internet: broman@nosc.mil   Uucp: sdcsvax!nosc!broman
-----------------cut here----------------------------------------------------
;;; Pascal editing support package in GNU Emacs Elisp.  v2.1
;;; Author: Vincent Broman <broman@nosc.mil>  February 1988.
;;;
;;; (borrows from Mick Jordan's modula-2-mode for Emacs,
;;; as modified by Peter Robinson, Michael Schmidt, and Tom Perrine.)
;;;
;;; Tries hard to do all the indenting automatically.
;;; Emphasizes correct insertion of new code, more than editing old code,
;;; although movement by indentation groups is supported.
;;;
;;; To do:   semiautomatic variable declaration.
;;;          quick duplication of subprogram specs needed for bodies or calls.
;;;          interface with abbrev-mode and/or outline-mode
;;;          finish the unused pascal-indent-line function
;;;

(let ((pascal-suffix "\\.pas$"))
  (if (null (assoc pascal-suffix auto-mode-alist))
    (setq auto-mode-alist (cons (cons pascal-suffix 'pascal-mode)
				auto-mode-alist))))
(let ((pascal-suffix "\\.p$"))
  (if (null (assoc pascal-suffix auto-mode-alist))
    (setq auto-mode-alist (cons (cons pascal-suffix 'pascal-mode)
				auto-mode-alist))))

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

(let ((pascal-tbl (make-syntax-table)))
  (modify-syntax-entry ?\_ "_" pascal-tbl)
  (modify-syntax-entry ?\$ "_" pascal-tbl)
  (modify-syntax-entry ?\# "_" pascal-tbl)
  (modify-syntax-entry ?\% "_" pascal-tbl)
  (modify-syntax-entry ?\( "()1" pascal-tbl)
  (modify-syntax-entry ?\) ")(4" pascal-tbl)
; unfortunately, (* *) comment sequences excite a bug in (blink-matching-open)
  (modify-syntax-entry ?\* ". 23" pascal-tbl)
  (modify-syntax-entry ?\/ "." pascal-tbl)
  (modify-syntax-entry ?\+ "." pascal-tbl)
  (modify-syntax-entry ?\- "." pascal-tbl)
  (modify-syntax-entry ?\= "." pascal-tbl)
  (modify-syntax-entry ?\& "." pascal-tbl)
  (modify-syntax-entry ?\| "." pascal-tbl)
  (modify-syntax-entry ?\< "." pascal-tbl)
  (modify-syntax-entry ?\> "." pascal-tbl)
  (modify-syntax-entry ?\[ "(]" pascal-tbl)
  (modify-syntax-entry ?\] ")[" pascal-tbl)
  (modify-syntax-entry ?\{ "<" pascal-tbl)
  (modify-syntax-entry ?\} ">" pascal-tbl)
  (modify-syntax-entry ?\. "." pascal-tbl)
  (modify-syntax-entry ?\\ "." pascal-tbl)
  (modify-syntax-entry ?\: "." pascal-tbl)
  (modify-syntax-entry ?\; "." pascal-tbl)
  (modify-syntax-entry ?\' "\"" pascal-tbl)
  (modify-syntax-entry ?\" "\"" pascal-tbl)
  (setq pascal-mode-syntax-table pascal-tbl))

(defvar pascal-mode-map nil
  "Keymap used in Pascal mode.")

(let ((pascal-mp (make-sparse-keymap)))
  (define-key pascal-mp "\C-m" 'pascal-newline)
  (define-key pascal-mp "\C-j" 'newline)
  (define-key pascal-mp "\C-c\C-m" 'pascal-openline)
  (define-key pascal-mp "\C-?" 'backward-delete-char-untabify)
  (define-key pascal-mp "\C-i" 'pascal-tab)
  (define-key pascal-mp "\C-c\C-i" 'pascal-untab)
  (define-key pascal-mp "\C-c<" 'pascal-backward-to-same-indent)
  (define-key pascal-mp "\C-c>" 'pascal-forward-to-same-indent)
  (define-key pascal-mp "\C-ch" 'pascal-header)
  (define-key pascal-mp "\C-c(" 'insert-parentheses)
  (define-key pascal-mp "\C-c[" 'insert-brackets)
  (define-key pascal-mp "\C-c{" 'pascal-comment)
  (define-key pascal-mp "\C-c*" 'pascal-star-display-comment)
  (define-key pascal-mp "\C-c\C-a" 'pascal-array)
  (define-key pascal-mp "\C-cb" 'pascal-begin)
  (define-key pascal-mp "\C-cc" 'pascal-case)
  (define-key pascal-mp "\C-c\C-c" 'pascal-const)
  (define-key pascal-mp "\C-c\C-e" 'pascal-elsif)
  (define-key pascal-mp "\C-ce" 'pascal-else)
  (define-key pascal-mp "\C-c\C-p" 'pascal-procedure-spec)
  (define-key pascal-mp "\C-cp" 'pascal-subprogram-body)
  (define-key pascal-mp "\C-c\C-f" 'pascal-function-spec)
  (define-key pascal-mp "\C-cf" 'pascal-for-loop)
  (define-key pascal-mp "\C-ci" 'pascal-if)
  (define-key pascal-mp "\C-c\C-r" 'pascal-record)
  (define-key pascal-mp "\C-cr" 'pascal-repeat)
  (define-key pascal-mp "\C-c\C-t" 'pascal-type)
  (define-key pascal-mp "\C-c\C-v" 'pascal-var)
  (define-key pascal-mp "\C-c\C-w" 'pascal-with)
  (define-key pascal-mp "\C-cw" 'pascal-while)
  (define-key pascal-mp "\C-c\C-x" 'pascal-external)
  (define-key pascal-mp "\C-c=" 'pascal-show-subprogram-name)
  (define-key pascal-mp "\C-cB" 'pascal-make-bind)
  (define-key pascal-mp "\C-cC" 'pascal-compile)
  (define-key pascal-mp "\C-cI" 'pascal-include-file)
  (define-key pascal-mp "\C-cK" 'pascal-togl-key-case)
  (define-key pascal-mp "\C-cM" 'pascal-main-for-bind)
  (define-key pascal-mp "\C-cO" 'dnpas-set-options)
  (define-key pascal-mp "\C-cP" 'pascal-program)
  (define-key pascal-mp "\C-cR" 'pasmat-buffer)
  (define-key pascal-mp "\C-cS" 'pascal-tabsize)
  (define-key pascal-mp "\C-cT" 'pascal-toggle-file)
  (setq pascal-mode-map pascal-mp))

(defvar pascal-edit-prefix "Last Mod: \t"
  "*String prefixed to the timestamp from the last pascal-mode edit of this file.")

(defvar pascal-openparen-style " ("
  "*The string inserted for open parens.  Spaces may precede or follow.")

(defvar pascal-closeparen-style ")"
  "*The string inserted for close parens.  Spaces may precede or follow.")

(defvar pascal-openbrack-style "["
  "*The string inserted for open brackets.  Spaces may precede or follow.")

(defvar pascal-closebrack-style "]"
  "*he string inserted for close brackets.  Spaces may precede or follow.")

(defvar pascal-indent 4
  "*Value is the number of columns to indent in Pascal Mode.")


(defun pascal-mode ()
"This is a mode intended to support program development in Pascal.
Most control constructs and declarations of Pascal can be inserted
by typing Control-C followed by a character mnemonic for the construct.
Generally, the functions expect to be invoked right after typing \\[pascal-newline],
except for array, record, and proc/func body which start at the end of a line.
Elements of the construct to insert are prompted for.  Optional elements have
prompts in square brackets[].
\\<pascal-mode-map>
C-c TAB  indent less    TAB      indent more
C-c C-a	 array          C-c b    begin end
C-c C-c  const          C-c c    case
C-c C-e	 else if        C-c e	 else
C-c C-f	 function spec  C-c f	 for loop
C-c {    comment        C-c h	 header comment section
                        C-c i	 if
C-c C-p	 procedure spec C-c p	 proc/func body
C-c C-r	 record         C-c r    repeat until
C-c C-t	 type
C-c C-v	 var
C-c C-w	 with           C-c w	 while
C-c C-x	 external       C-c =    show subprog name
C-c (	 paired parens  C-c [	 paired brackets
C-c B	 make and bind  C-c C	 compile
C-c I    include        C-c K	 keyword case
C-c M    main obj       C-c O	 comp options   
C-c P    program stmnt  C-c R    reformat source
C-c S	 set tab size   C-c T	 toggle between body and spec

\\[pascal-backward-to-same-indent] and \\[pascal-forward-to-same-indent] move backward and forward respectively to the next line having
the same (or lesser) level of indentation, passing over labels and comments.

The number of spaces for used for indenting/undenting
is controllable by doing \\[pascal-tabsize]

Other commands of potential interest are
pascal-resize-indent-whole-buffer
pascal-backward-to-less-indent
pascal-forward-to-less-indent
"
  (interactive)
  (kill-all-local-variables)
  (use-local-map pascal-mode-map)
  (set-syntax-table pascal-mode-syntax-table)
  (setq major-mode 'pascal-mode)
  (setq mode-name "Pascal")
;;;
  (make-local-variable 'paragraph-start)
  (setq paragraph-start (concat "^$\\|" page-delimiter))
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
  (make-local-variable 'require-final-newline)
  (setq require-final-newline t)
;;;
  (make-local-variable 'comment-start)
  (setq comment-start "{")
  (make-local-variable 'comment-end)
  (setq comment-end "}")
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "{[ \t]*\\|(\\*[ \t]*")
  (setq comment-column 35)
  (make-local-variable 'end-comment-column)
  (setq end-comment-column 60)
  (make-local-variable 'comment-indent-hook)
  (setq comment-indent-hook 'pascal-comment-indent)
  (make-local-variable 'comment-multi-line)
  (setq comment-multi-line t)
  (make-local-variable 'parse-sexp-ignore-comments)
  (setq parse-sexp-ignore-comments t)
  (make-local-variable 'pascal-end-of-subprog-hdg)
  (setq pascal-end-of-subprog-hdg nil)
  ;; value of point at end of procedure or function heading.
  ;; set by pascal-get-arg-list. made nil after pascal-newline.
  (pascal-update-timestamp)
  (run-hooks 'pascal-mode-hook))


(defun pascal-tabsize (s)
  "Changes spacing used for indentation. Reads spacing from minibuffer."
  (interactive "nnew indentation spacing: ")
  (setq pascal-indent s))

(defun pascal-prev-line-ends-heading ()
;;; Predicate indicates whether the value of point saved right after
;;; creating a subprogram heading lies on the previous line.
  (and
    pascal-end-of-subprog-hdg
    (save-excursion
      (end-of-line 0)
      (let ((pascal-point-eol (point)))
	(forward-line 0)
	(and
	  (< (point) pascal-end-of-subprog-hdg)
	  (<=        pascal-end-of-subprog-hdg pascal-point-eol))))))

(defun pascal-indent-after-heading ()
;;; Returns the amount of indentation desired
;;; on the line just after a subprogram heading with no body.
  (+ pascal-indent (cdr (pascal-get-subprogram-name))))

(defun pascal-newline ()
  "Start new line and indent to current tab stop."
  (interactive)
  (let ((pascal-cc (current-indentation)))
    (newline)
    (indent-to pascal-cc)
    (if (pascal-prev-line-ends-heading)
	(progn
	  (pascal-tab)
	  (let ((indentwanted (pascal-indent-after-heading)))
	    (delete-horizontal-space)
	    (indent-to indentwanted))))
    (setq pascal-end-of-subprog-hdg nil)))

(defun pascal-openline ()
  "Start new line ahead of this line and indent to current tab stop."
  (interactive)
  (let ((pascal-cc (current-indentation)))
    (beginning-of-line)
    (open-line 1)
    (indent-to pascal-cc)))

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

(defun pascal-untab ()
  "Delete backwards from current indentation to previous tab stop."
  (interactive)
  (let ((pascal-cc (current-indentation)))
    (if (> pascal-cc 0)
	(progn
	  (back-to-indentation)
	  (backward-delete-char-untabify
	    (1+ (mod (1- pascal-cc) pascal-indent)) nil)))))

(defun pascal-two-lines-one-indented ()
;;; Insert two newlines, the first indented again, the second not.
  (pascal-newline)
  (pascal-tab)
  (pascal-newline)
  (pascal-untab))

(defun pascal-comment-and-temp-indent ()
;;; Insert three newlines, the first before a comment line,
;;; the second temporarily indented again, the third not.
  (let ((pascal-indentation (current-indentation)))
    (insert "\n" comment-start comment-end "\n")
    (indent-to pascal-indentation))
  (pascal-tab)
  (pascal-newline)
  (pascal-untab))


;assume no nested comments {{}} or (*(**)*)

(defun looking-back-at (string)
;;;like (looking-at) but checks chars before point against string (not regexp)
  (let ((stringstart (- (point) (length string))))
    (and
      (>= stringstart (point-min))
      (string-equal string (buffer-substring stringstart (point))))))

(defun pascal-skip-forward-white ()
;;;move point forward past any white space or comments
  (skip-chars-forward "\t- " (point-max))
  (while (looking-at "{")
    (search-forward "}" (point-max) 'move)
    (skip-chars-forward "\t- " (point-max))
    (while (looking-at "(\\*")
      (forward-char 2)
      (search-forward "*)" (point-max) 'move)
      (skip-chars-forward "\t- " (point-max))))
  (< (point) (point-max)))

(defun pascal-next-code ()
;;;move point to next line and past any white space or comments preceding code.
  (end-of-line 1)
  (pascal-skip-forward-white))

(defun pascal-skip-backward-white ()
;;;move point backward past any white space or comments
  (skip-chars-backward "\t- " (point-min))
  (while (looking-back-at "}")
    (search-backward "{" (point-min) 'move)
    (skip-chars-backward "\t- " (point-min))
    (while (looking-back-at "*)")
      (backward-char 2)
      (search-backward "(*" (point-min) 'move)
      (skip-chars-backward "\t- " (point-min))))
  (> (point) (point-min)))

(defun pascal-prev-code ()
;;;move point back to nearest previous line containing code (anything besides
;;;whitespace or comments) and move to the first code found on that line.
  (if (pascal-skip-backward-white)
      (progn
	(beginning-of-line)
	(pascal-skip-forward-white))
    nil))

(defun pascal-backward-to-this-indent (indent-level)
  "Move point back one or more lines to the start of code on the line,
until the indentation is INDENT-LEVEL or less or the start of buffer is hit.
Ignore comments, blank lines, and statement labels.
Return success predicate."
  (let ((gofurther t))
    (while (and
	     (pascal-prev-code)
	     (or
	       (looking-at "^[A-Za-z0-9_$]+:[^=]")
	       (setq gofurther (> (current-column) indent-level)))))
    (not gofurther)))

(defun pascal-forward-to-this-indent (indent-level)
  "Move point foreward one or more lines to the start of code on the line,
until the indentation is INDENT-LEVEL or less or the end of buffer is hit.
Ignore comments, blank lines, and statement labels.
Return success predicate."
  (let ((gofurther t))
    (while (and
	     (pascal-next-code)
	     (or
	       (looking-at "^[A-Za-z0-9_$]+:[^=]")
	       (setq gofurther (> (current-column) indent-level)))))
    (not gofurther)))

(defun pascal-backward-to-same-indent ()
  "Move point backwards to nearest line with same indentation or less.
If not found, point is left at top of buffer.
Success predicate is returned."
  (interactive)
  (pascal-backward-to-this-indent (current-indentation)))

(defun pascal-forward-to-same-indent ()
  "Move point forwards to nearest line with same indentation or less.
If not found, point is left at start of last line in buffer.
Success predicate is returned."
  (interactive)
  (pascal-forward-to-this-indent (current-indentation)))

(defun pascal-backward-to-less-indent ()
  "Move point backwards to nearest line with less indentation.
If not found, point is left at top of buffer.
Success predicate is returned."
  (interactive)
  (pascal-backward-to-this-indent (max 0 (1- (current-indentation)))))

(defun pascal-forward-to-less-indent ()
  "Move point forwards to nearest line with less indentation.
If not found, point is left at start of last line in buffer.
Success predicate is returned."
  (interactive)
  (pascal-forward-to-this-indent (max 0 (1- (current-indentation)))))


(defun pascal-start-insert-here ()
  "Remember that point is the start of a long construct being inserted.
This makes an undo after the insertion retreat to this point."
  (undo-boundary))

(defun pascal-end-insert-here ()
  "Remember point as the end of a long construct being inserted.
Also, make this point and the following line visible on screen if it is not.
This function might be called repeatedly during any one insertion,
because of all the opportunities for keyboard interrupts during read-string."
  (save-excursion
    (end-of-line 2)
    (if (not (pos-visible-in-window-p))
	(recenter -1))))

(defun pascal-end-insert-at (pascal-line-offset)
  "Remember the point at the end of pascal-line-offset lines following
the current line as being the end of a long construct being inserted."
  (save-excursion
    (end-of-line (1+ pascal-line-offset))
    (pascal-end-insert-here)))

(defun pascal-end-subproghdg-insert-here ()
;;; End insertion here and also remember point as the end of
;;; a subprogram heading.
;;; This affects the indentation of the next pascal-newline.
  (pascal-end-insert-here)
  (setq pascal-end-of-subprog-hdg (point)))


(defvar pascal-upper-keys nil
  "*Flag desire for uppercase pascal keywords")

(defun pascal-togl-key-case ()
  "Functions toggles the value of the boolean pascal-upper-keys."
  (interactive)
  (setq pascal-upper-keys (not pascal-upper-keys))
  (message (concat "key words will now be "
		   (if pascal-upper-keys "UPPER" "lower")
		   " case.")))

(defun pascal-key (s)
  "Change case of string to be appropriate for pascal keywords."
  (if pascal-upper-keys (upcase s) (downcase s)))


(defun pascal-array ()
  "Add an array type definition,
prompting for the component type and the index subtypes."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "array") pascal-openbrack-style pascal-closebrack-style)
  (pascal-end-insert-here)
  (backward-char (length pascal-closebrack-style))
  (insert (read-string "index range(s): "))
  (end-of-line)
  (insert (pascal-key " of ;"))
  (pascal-end-insert-here)
  (backward-char)
  (insert (read-string "component type: "))
  (end-of-line)
  (pascal-end-insert-here))

(defun pascal-begin ()
  "Build a begin-end statement, prompting for a comment."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "begin"))
  (pascal-newline)
  (pascal-newline)
  (insert (pascal-key "end") "; {}")
  (backward-char 1)
  (let ((pascal-comment (read-string "comment about block: ")))
    (if (string-equal pascal-comment "")
	(progn
	  (end-of-line)
	  (backward-delete-char 3))
      (progn
	(insert pascal-comment)
	(end-of-line))))
  (pascal-end-insert-here)
  (end-of-line 0))

(defun pascal-case ()
  "Build skeleton case statement, prompting for the selector expression."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "case "))
  (pascal-end-insert-here)
  (insert (read-string "selector expression: ") (pascal-key " of"))
  (pascal-two-lines-one-indented)
  (insert (pascal-key "end") "; {case}")
  (pascal-end-insert-here)
  (end-of-line 0))

(defun pascal-rm-semi-before-else ()
;;; Delete a semicolon, if present, ending the preceding code line.
  (save-excursion
    (if (pascal-prev-code-line)
	(progn
	  (pascal-goto-end-of-code)
	  (if (equal ?\; (char-after (1- (point))))
	      (backward-delete-char 1))))))


(defun pascal-else ()
  "Add an else clause after an if-then.
Tries to delete an extraneous semicolon which might precede the else."
  (interactive)
  (pascal-start-insert-here)
  (pascal-rm-semi-before-else)
  (pascal-untab)
  (insert (pascal-key "else"))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-for-loop ()
  "Build a skeleton for statement, prompting for the loop parameters."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "for "))
  (pascal-end-insert-here)
  (insert (read-string "loop variable: ") " :=  " (pascal-key "do"))
  (pascal-end-insert-here)
  (backward-char 3)			;length of " do"
  (insert (read-string "range: "))
  (end-of-line)
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-if ()
  "Insert skeleton if statement, prompting for the boolean-expression."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "if "))
  (pascal-end-insert-here)
  (insert (read-string "condition: ") (pascal-key " then"))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-elsif ()
  "Add an else if clause to an if statement,
prompting for the boolean-expression."
  (interactive)
  (pascal-start-insert-here)
  (pascal-rm-semi-before-else)
  (pascal-untab)
  (insert (pascal-key "else if "))
  (pascal-end-insert-here)
  (insert (read-string "condition: ") (pascal-key " then"))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-insert-with-semi (pascal-str)
;;; Insert string and append semicolon if not present at end thereof.
  (insert pascal-str)
  (if (not (string-match ";$" pascal-str))
      (insert ";")))

(defun pascal-get-arg-list ()
  "Read from user a procedure or function argument list.
Add parens if one or more arguments are supplied, and insert into buffer.
Individual argument specs are stacked vertically if entered one-at-a-time.
The argument list is terminated when a CR is given instead of an argument."
  (insert pascal-openparen-style)
  (pascal-end-insert-here)
  (let ((pascal-arg-indent (current-column))
	(pascal-arg (read-string "[argument and type]: ")))
    (if (string-equal pascal-arg "")
	(backward-delete-char (length pascal-openparen-style))
      (progn
	(while (not (string-equal "" pascal-arg))
	  (pascal-insert-with-semi pascal-arg)
	  (newline)
	  (indent-to pascal-arg-indent)
          (pascal-end-insert-here)
	  (setq pascal-arg (read-string "[next argument and type]: ")))
	(delete-horizontal-space)
	(backward-delete-char 2)	; NewLine and SemiColon
	(insert pascal-closeparen-style))))
  (pascal-end-subproghdg-insert-here))

(defun pascal-function-spec (pascal-nested)
  "Insert a function specification.
Prompts for name and arguments and result type.
If given a prefix arg, indentation is chosen which assumes
the function declaration is nested inside another subprogram."
  (interactive "P")
  (pascal-start-insert-here)
  (let ((pascal-prev-indent (cdr (pascal-get-subprogram-name))))
    (delete-horizontal-space)
    (indent-to (if pascal-nested
		   (+ pascal-prev-indent pascal-indent)
		 pascal-prev-indent)))
  (insert (pascal-key "function "))
  (pascal-end-insert-here)
  (insert (read-string "function name: "))
  (pascal-get-arg-list)
  (insert ": ")
  (pascal-end-insert-here)
  (insert (read-string "result type: ") ";")
  (pascal-end-subproghdg-insert-here))

(defun pascal-procedure-spec (pascal-nested)
  "Insert a procedure specification, prompting for its name and arguments.
If given a prefix arg, indentation is chosen which assumes
the procedure declaration is nested inside another subprogram."
  (interactive "P")
  (pascal-start-insert-here)
  (let ((pascal-prev-indent (cdr (pascal-get-subprogram-name))))
    (delete-horizontal-space)
    (indent-to (if pascal-nested
		   (+ pascal-prev-indent pascal-indent)
		 pascal-prev-indent)))
  (insert (pascal-key "procedure "))
  (pascal-end-insert-here)
  (insert (read-string "procedure name: " ))
  (pascal-get-arg-list)
  (insert ";")
  (pascal-end-subproghdg-insert-here))

(defun pascal-am-in-comment ()
  "Predicate indicates whether point is in the 1st line of a comment,
i.e. past the beginning of the comment introducer."
  (let ((pascal-opoint (point))
	(pascal-eol (save-excursion (end-of-line) (point))))
    (save-excursion
      (beginning-of-line)
      (if (re-search-forward comment-start-skip pascal-eol 'keep-going)
	  (> pascal-opoint (match-beginning 0))
	nil))))

(defun pascal-get-subprogram-name ()
  "Return (without moving point or mark) a pair whose CAR is
the name associated with the function or procedure statement
 which immediately precedes point,
and whose CDR is the column number at which the
function/procedure keyword was found."
  (save-excursion
    (let ((keyword-regex "\\(procedure\\|function\\|program\\)\\>")
	  (case-fold-search t))		; note dynamic binding
      (while (and
	       (pascal-backward-to-less-indent)
	       (not (looking-at keyword-regex)))
	nil)
      (if (looking-at keyword-regex)
	  (let ((pascal-proc-indent (current-column)))
	    (forward-sexp 2)
	    (let ((p2 (point)))
	      (forward-sexp -1)
	      (cons (buffer-substring (point) p2) pascal-proc-indent)))
	(cons "NAME?" 0)))))

(defun pascal-subprogram-body ()
  "Insert frame for subprogram body.  Invoke right after
pascal-function-spec or pascal-procedure-spec at end of line."
  (interactive)
  (pascal-start-insert-here)
  (pascal-newline)
  (let ((pascal-subprogram-name-col (pascal-get-subprogram-name)))
    (delete-horizontal-space)
    (insert comment-start comment-end "\n")
    (indent-to (cdr pascal-subprogram-name-col))
    (pascal-tab)
    (pascal-newline)
    (insert (pascal-key "begin"))
    (pascal-two-lines-one-indented)
    (insert (pascal-key "end") "; {" (car pascal-subprogram-name-col) "}"))
  (pascal-end-insert-here)
  (end-of-line -2))

(defun pascal-show-subprogram-name ()
  "Display in the echo area the name of the subprogram
in the closest procedure or function header found before point.
Simple minded."
  (interactive)
  (let ((pascal-sub-name (pascal-get-subprogram-name)))
    (message (concat "subprogram name is " (car pascal-sub-name) "."))))

(defun pascal-program ()
  "Insert a program statement, prompting for its name and filelist."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "program "))
  (pascal-end-insert-here)
  (insert (read-string "program name: "))
  (insert pascal-openparen-style pascal-closeparen-style ";")
  (pascal-end-insert-here)
  (backward-char (1+ (length pascal-closeparen-style)))
  (let ((pascal-filelist (read-string "program header list: ")))
    (if (string-equal pascal-filelist "")
	(progn
	  (backward-char (length pascal-openparen-style))
	  (kill-line nil)
	  (insert ";"))
      (progn
	(insert pascal-filelist)
	(end-of-line))))
  (pascal-comment-and-temp-indent)
  (insert (pascal-key "begin"))
  (pascal-two-lines-one-indented)
  (insert (pascal-key "end") ". {Program}")
  (pascal-end-insert-here)
  (end-of-line -2))


(defun pascal-record ()
  "Insert a skeleton record type declaration."
  (interactive)
  (pascal-start-insert-here)
  (if (not (point-on-blank-line))
      (progn
	(end-of-line)
	(pascal-newline)
	(pascal-tab)))
  (insert (pascal-key "record"))
  (pascal-two-lines-one-indented)
  (insert (pascal-key "end") "; {record}")
  (pascal-end-insert-here)
  (end-of-line 0))

(defun pascal-repeat ()
  "Create a repeat until statement."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "repeat"))
  (pascal-two-lines-one-indented)
  (insert (pascal-key "until ;"))
  (pascal-end-insert-here)
  (backward-char 1)
  (insert (read-string "exit condition: "))
  (end-of-line)
  (pascal-end-insert-here)
  (end-of-line 0))

(defun pascal-header-section (pascal-secname)
;;; Start a const, type, or var declaration section.
  (pascal-start-insert-here)
  (pascal-tab)
  (let ((procindent (cdr (pascal-get-subprogram-name))))
    (delete-horizontal-space)
    (indent-to procindent))
  (pascal-tab)
  (insert (pascal-key pascal-secname))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-const ()
  "Start a const section."
  (interactive)
  (pascal-header-section "const"))

(defun pascal-type ()
  "Start a type section."
  (interactive)
  (pascal-header-section "type"))

(defun pascal-var ()
  "Start a var section."
  (interactive)
  (pascal-header-section "var"))

(defun pascal-with ()
  "Create a with statement."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "with "))
  (pascal-end-insert-here)
  (insert (read-string "records to with: ") (pascal-key " do"))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-while ()
  "Create a while statement."
  (interactive)
  (pascal-start-insert-here)
  (insert (pascal-key "while "))
  (pascal-end-insert-here)
  (insert (read-string "entry condition: ") (pascal-key " do"))
  (pascal-newline)
  (pascal-tab)
  (pascal-end-insert-here))

(defun pascal-external ()
  "Create an extern or external statement."
  (interactive)
  (pascal-start-insert-here)
  (if (not (point-on-blank-line))
      (progn
	(end-of-line)
	(pascal-newline)))
  (let ((indentto (cdr (pascal-get-subprogram-name))))
    (delete-horizontal-space)
    (indent-to indentto))
  (pascal-tab)
  (insert (pascal-key (if pascal-from-berkeley "external;" "extern;")))
  (pascal-newline)
  (pascal-untab)
  (pascal-end-insert-here))

(defun pascal-include-file ()
  "Create a file inclusion statement."
  (interactive)
  (pascal-start-insert-here)
  (if (point-on-blank-line)
      (delete-horizontal-space)
    (progn
      (end-of-line)
      (insert "\n")))
  (insert (pascal-key (if pascal-from-berkeley
			  "#include \"\""
			"%include '';")))
  (pascal-end-insert-here)
  (backward-sexp 1)
  (forward-char 1)
  (insert (read-string "header file to include: "))
  (end-of-line)
  (pascal-end-insert-here))

(defun insert-brackets (arg)
  "Put square brackets around next ARG sexps.  Leave point after open-brack.
No argument is equivalent to zero: just insert [] and leave point between."
  (interactive "P")
  (insert "[")
  (save-excursion
    (if arg
	(forward-sexp (prefix-numeric-value arg)))
    (insert "]")))

(defun pascal-update-timestamp ()
  "Update the Last Mod: timestamp if found near the start of the buffer."
  (if (not buffer-read-only)
      (save-excursion
	(let ((pascal-buf-was-mod (buffer-modified-p))
	      (pascal-last-edit-marker pascal-edit-prefix))
	  (goto-char (point-min))
	  (if (re-search-forward
		pascal-last-edit-marker (+ 2000 (point-min)) t)
	      (progn
		(delete-char (- (save-excursion (end-of-line) (point))
				(point)))
		(insert (current-time-string))
		(set-buffer-modified-p pascal-buf-was-mod)))))))

(defun pascal-header (pascal-note-copyright)
  "Insert a comment block containing the module title, author, etc.
If given a prefix arg, make a copyright notice instead of an Author: entry."
  (interactive "P")
  (pascal-start-insert-here)
  (if (point-on-blank-line)
      (delete-horizontal-space)
    (progn
      (end-of-line)
      (newline)))
  (insert "{\n    Title: \t\n}")
  (pascal-end-insert-here)
  (end-of-line 0)
  (insert (read-string "Title: "))
  (insert "\n    " pascal-edit-prefix (current-time-string))
  (insert "\n    ")
  (if pascal-note-copyright
      (insert "Copyright \t" (substring (current-time-string) -4) " ")
    (insert   "Author: \t"))
  (insert (user-full-name) "\n\t\t<" (user-login-name) "@" (system-name) ">")
  (end-of-line 2)
  (pascal-end-insert-here))

(defun point-on-blank-line ()
  "Tell whether point is on a blank line or not."
  (save-excursion
    (beginning-of-line)
    (looking-at "^[ \t\f]*$")))

(defun pascal-comment (pascal-display-comment)
  "Insert a comment at end of this line, unless a prefix argument is given,
in which case a display comment following this line is created.
Inline comments start to the right of comment-column,
unless now past end-comment-column, in which case we start on the next line."
  (interactive "P")
  (end-of-line)
  (pascal-start-insert-here)
  (if pascal-display-comment
      (progn
	(if (point-on-blank-line)
	    (progn
	      (delete-horizontal-space))
	  (progn
	    (end-of-line)
	    (newline)))
	(insert comment-start "\n    \n" comment-end))
    (progn
      (if (> (current-column) end-comment-column) (newline))
      (indent-for-comment)))
  (pascal-end-insert-here)
  (if pascal-display-comment
      (end-of-line 0)))

(defun pascal-star-display-comment ()
  "Insert a (* *) display comment following this line."
  (interactive)
  (pascal-start-insert-here)
  (end-of-line)
  (if (point-on-blank-line)
      (delete-horizontal-space)
    (progn
      (end-of-line)
      (insert "\n")))
  (insert "(*\n *")
  (pascal-tab)
  (insert "\n *)")
  (pascal-end-insert-here)
  (end-of-line 0))

(defun pascal-comment-indent ()
  "Compute indent column for comment here."
  (if (and
	(= (current-column) 0)
	(or
	  (looking-at "{")
	  (looking-at "(\\*")
	  (= comment-column 0)))
      0
    (save-excursion
      (skip-chars-backward " \t\f")
      (max comment-column
	   (1+ (current-column))))))

(defun resize-indent-one-line (otab newtab)
  "Reindent the current line, subservient to resize-indent-whole-buffer."
  (back-to-indentation)
  (let ((curindent (current-indentation)))
    (delete-backward-char
      (- (point)
	 (save-excursion (beginning-of-line) (point))))
    (indent-to
       (+
	 (* newtab (/ curindent otab))	; whole tabs
	 (min newtab (mod curindent otab)) ; partial tabs
	 ))))

(defun resize-indent-whole-buffer (old-tab-size new-tab-size)
  "Change the indentation of all lines, using a user-supplied
old tab-spacing and a new tab-spacing.
Odd leading spaces are preserved so far as they are smaller
than the new tab spacing."
  (interactive "nold tab-size: \nnnew tab-size: ")
  (if (< old-tab-size 1)
      (message "old tab-size must be positive")
    (if (< new-tab-size 0)
	(message "new tab-size must be nonnegative")
      (progn
	(goto-char (point-min))
	(resize-indent-one-line old-tab-size new-tab-size)
	(while (= (forward-line 1) 0)
	  (resize-indent-one-line old-tab-size new-tab-size))))))


(defun pascal-prev-code-line ()
  "Move back to start of nearest preceding line containing code,
i.e. is not whitespace, a label, nor a comment.
Return nil if no such line found before beginning-of-buffer,
otherwise returns point from beginning of that line."
  (let ((pascal-no-code t))
    (while (and
	     (pascal-prev-code)
	     (setq pascal-no-code (looking-at "[A-Za-z0-9_$]+:[^=]")))
      nil)
    (if pascal-no-code nil (point))))

(defun pascal-goto-end-of-code ()
  "Move point on same line to end of code,
preceding any trailing whitespace or comment on the line.
Assumes point is on the beginning-of-line already."
  (let ((pascal-eol-point (save-excursion (end-of-line) (point))))
    (if (re-search-forward comment-start-skip pascal-eol-point 'keep-going)
	(goto-char (match-beginning 0))))
  (skip-chars-backward " \t\f"))

(defun string-match-list (sm-list-of-regex sm-list-candidate)
  (if sm-list-of-regex
      (if (string-match (car sm-list-of-regex) sm-list-candidate)
	  t
	(string-match-list (cdr sm-list-of-regex sm-list-candidate)))
    nil))
		   

(defun pascal-prev-line-continued-at ()
  "Returns a column for code continuing a previous line to begin on,
or else nil, in case the previous line is complete or nonexistent."
  (save-excursion
    (if (pascal-prev-code-line)
	(let ((pascal-bol-point (point)))
	  (pascal-goto-end-of-code)
	  (if (string-match-list pascal-line-enders
				 (buffer-substring pascal-bol-point (point)))
	      nil			; line is complete
	    (+ (current-indentation) 1 (/ (1- pascal-indent) 2))))
      nil)))				; there is no prev code line

;;;
;;; unfinished, just confirms current indent for hard cases.
;;; 
(defun pascal-related-indent (pascal-nxt-pt pascal-nxt-key pascal-prev-pt pascal-prev-key)
  (save-excursion
    (goto-char pascal-nxt-pt)
    (current-indentation)))

(defun pascal-get-starter ()
  (buffer-substring (point)
		    (save-excursion
		      (skip-chars-forward "A-Za-z0-9_$"))))

(defun pascal-compute-indentation ()
  "Return column nbr appropriate for this line of Pascal code.
Assumes point is at the current indentation."
  (save-excursion
    (let ((case-fold-search t)
	  (pascal-opoint (point)))
      (cond
	((looking-at comment-start-skip)
	 (pascal-comment-indent))
	((looking-at "[a-z0-9_$]+:[^=]")
	 0)
	((pascal-prev-line-continued-at))
	(t
	  (let (pascal-prev-point pascal-prev-key)
	    (save-excursion
	      (setq pascal-prev-point (pascal-prev-code-line))
	      (if pascal-prev-point (setq pascal-prev-key (pascal-get-starter))))
	    (if pascal-prev-point
		(pascal-related-indent (point) (pascal-get-starter)
				    pascal-prev-point pascal-prev-key)
	      0)))))))

(defun pascal-indent-line ()
  "Reindent current line to column appropriate for the code.
Mainly checks the near left context."
  (interactive)
  (let* ((pascal-beyond-indent (max 0 (- (point)
				      (progn (back-to-indentation) (point)))))
	 (pascal-computed-indentation (pascal-compute-indentation)))
    (delete-backward-char
      (- (point)
	 (save-excursion (beginning-of-line) (point))))
    (indent-to (pascal-computed-indentation))
    (forward-char pascal-beyond-indent)))

(defvar pascal-line-enders
  '(
  "^.*;"
  )
  "List of regexps which match code which can belong on the end of a line,
Even if infinite room were available for long lines.")


(defun pascal-toggle-file ()
;;; assumes specification file has name of form: name.h
;;;              and body file has name of form: name.pas or name.p
  "Toggle between body and specification files for the program."
  (interactive)
  (cond
    ((string-equal (substring (buffer-file-name) -4) ".pas")
     (find-file-other-window
       (concat (substring (buffer-file-name) 0 -4) ".h")))
    ((string-equal (substring (buffer-file-name) -2) ".p")
     (find-file-other-window
       (concat (substring (buffer-file-name) 0 -2)  ".h")))
    ((string-equal (substring (buffer-file-name) -2) ".h")
     (find-file-other-window
       (let ((pascal-file (concat (substring (buffer-file-name) 0 -2)
				  ".pas")))
	 (if (file-readable-p pascal-file)
	     pascal-file
	   (substring pascal-file -2)))))
    (t
      (error "pascal-toggle-file does not know how to find the other file."))))


(defvar pascal-from-berkeley (let ((vers "(berkeley-unix)"))
			       (string-equal
				 (substring (emacs-version) (- (length vers)))
				 vers))
  "*Flag indicating pascal compiler used is berkeley pc.")


;;; compilation code for Domain Pascal and Berkeley pc compilers

(defun pascal-compile ()
  "Compile pascal program."
  (interactive)
  (compile (if pascal-from-berkeley
	       (concat "pc -c " pascal-compile-opts " " (buffer-file-name))
	     (concat "pas " (buffer-file-name) " " pascal-compile-opts))))

(defun dnpas-make-bind ()
  "Compile and link program by making."
  (interactive)
  (compile (concat "make " (pascal-main-prog))))


(defvar pascal-compile-opts ""
  "*Options to supply for Pascal compiling.")

(defun dnpas-set-options ()
  "Specify options needed for Domain Pascal compiler.
Empty responses cause no change; blank responses nullify the previous options."
  (interactive)
  (let ((pascal-options (read-string "options for pascal compile: ")))
    (if (not (string-equal pascal-options ""))
	(setq pascal-compile-opts pascal-options))))

(defvar pascal-main-prog "" "*Name of main program for binding.")
(defun pascal-main-prog ()
  "Supply name of main program unit needed for binding."
  (while (string-match "^[ \t\f]$" pascal-main-prog)
    (call-interactively 'pascal-main-for-bind))
  pascal-main-prog)

(defun pascal-main-for-bind (pascal-main)
  "Specify name of main program unit needed for binding."
  (interactive "sname of executable program to be made: ")
  (setq pascal-main-prog pascal-main))


(defun pasmat-buffer ()
  "Save buffer and replace Pascal source with reformatted version."
  (interactive)
  (let ((oldbuffer (current-buffer))
	(bufwasmod (buffer-modified-p))
	(tmpbuffer nil)
	(sourcename nil))
    (unwind-protect
	(progn
	  (if bufwasmod (save-buffer))
	  (setq sourcename (buffer-file-name))
	  (setq tmpbuffer (get-buffer-create "*Pascal Pasmat*"))
	  (set-buffer tmpbuffer)
	  (erase-buffer)
	  (message (if bufwasmod
		       "buffer saved, running pasmat..."
		     "running pasmat..."))
	  (call-process "pasmat"
			nil t nil
			"-s"
			(concat "{r"
				(if pascal-upper-keys "+" "-")
				",t="
				(int-to-string pascal-indent)
				"}")
			sourcename)
	  (goto-char (point-min))
	  (set-buffer-modified-p nil)
	  (set-buffer oldbuffer)
	  (undo-boundary)
	  (goto-char (point-min))
	  (insert-buffer-substring tmpbuffer) ;add the new
	  (delete-region (point) (point-max)) ;takeaway the old
	  (message "running pasmat... done."))
      (set-buffer oldbuffer)
      (if tmpbuffer (kill-buffer tmpbuffer)))))

mosurm@mntgfx.mentor.com (Mosur Mohan) (10/12/88)

In article <23772@tut.cis.ohio-state.edu>, bob@banjo.cis.ohio-state.edu
(Bob Sutterfield) writes:
> In article <LAZLOR.88Oct5210131@ucscb.UCSC.EDU> lazlor@ucscb.UCSC.EDU
> (Allen) writes:
> >I am looking for a Pascal Minor mode for Gnu Emacs.

> "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
> 

Well, I had looked at the Modula mode (which looks very similar to
this Pascal mode), and then hacked up my own version of Pascal mode
with an emphasis on indentation and scanning begin-end blocks rather
than on producing templates for the various Pascal structured
statements (which to me seemed rather less useful).  Here's the
describe-mode output on my pas-mode; if folks are interested, I can
post my version (although it ain't quite as well finished as I might
have hoped for the purposes of distribution).  (I had mailed it out
once to someone who had requested it, but got no response nor ack.)
======================================================================
Pascal Mode:
Mode to support program development in Pascal.
The prefix-key for pas-mode is Ctrl-C.

  TAB            pas-indent-line  | Ctrl-c TAB     pas-tab-to-tab-col
  Ctrl-j         pas-newline      | Ctrl-c b       pas-begin
  Ctrl-c Ctrl-f  forward-block    | Ctrl-c Ctrl-b  backward-block
  Ctrl-c Ctrl-d  down-block       | Ctrl-c Ctrl-u  back-up-block
  Ctrl-c Ctrl-e  up-block         | Ctrl-c Ctrl-@  mark-block
  Ctrl-c Ctrl-n  narrow-to-block  | Ctrl-c ~       self-assign-stmt
  Ctrl-c Ctrl-[  open-comment-box | Ctrl-c Ctrl-m  continue-comment-box
  Ctrl-c }       pas-end-comment  | Ctrl-c >       set-end-comment-column

Variables:
  pas-indent controls the number of spaces for each indentation
  pas-tab-col controls the column to tab to using \C-c <TAB>
  end-comment-column controls the column on which comments will be closed
==============================================================================
Notes:
  * the "blocks" referred to are begin-end, case-end, record-end and
  repeat-until blocks; block-functions mirror lisp-mode functions

  * the self-assign-stmt is a simple hack to get the oft-used "x := x + 1"
  without having to retype the " := x " part of it; real useful when x
  is a long identifier or sequence of pointer-references.

  * pas-newline and pas-indent-line compute the correct indentation by
  referring to the indentation of the enclosing block.

Enjoy!  -- Mohan.  {Mosur Mohan, Mentor Graphics, Beaverton, OR}
                   {uunet!mntgfx!mosurm}

"Do not meddle in the affairs of wizards, for they are subtle, and
quick to anger."  -- Gildor Inglorion in _The Fellowship of the Ring_

mosurm@mntgfx.mentor.com (Mosur Mohan) (10/19/88)

Here's the pascal-mode I wrote, with capabilities to scan blocks and
do a reasonably good job of auto-indenting code.  I also modified the
etags program to build tags for Pascal code (unfortunately, not for
type-declarations, I didn't have time to get to that); I'll post the
etags program separately.

Enjoy!  -- Mohan.   {uunet!mntgfx!mosurm}
                    {Mosur Mohan, Mentor Graphics, Beaverton, OR}
================================================================================
;;; Modified by Mosur Mohan 15-Apr-88 <uunet!mntgfx!mosurm> 
;;; Pascal editing support package, based on:

;; Originally, Modula-2 editing support package
;; Author Mick Jordan
;; Amended Peter Robinson
;; Ported to GNU Michael Schmidt
;; From: "Michael Schmidt" <michael@pbinfo.UUCP>
;;; Modified by Tom Perrine <Perrin@LOGICON.ARPA> (TEP)

(defvar pas-mode-syntax-table nil
  "Syntax table in use in Pascal-mode buffers.")
(defvar pas-mode-abbrev-table nil
  "Abbrev table in use in pas-mode buffers.")
(define-abbrev-table 'pas-mode-abbrev-table ())

(if pas-mode-syntax-table
    ()
  (let ((table (make-syntax-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 ?_ "w" table)
    (modify-syntax-entry ?\' "\"" table)
    (setq pas-mode-syntax-table table)))

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

(if pas-mode-map ()
  (let ((map (make-sparse-keymap)))
    (define-key map "\C-i" 'pas-indent-line)
    (define-key map "\C-c\C-i" 'pas-tab-to-tab-col)
    (define-key map "\C-j" 'pas-newline)
    (define-key map "\C-cb" 'pas-begin)
    (define-key map "\C-c\C-b" 'backward-block)
    (define-key map "\C-c\C-f" 'forward-block)
    (define-key map "\C-c\C-d" 'down-block)
    (define-key map "\C-c\C-e" 'up-block)
    (define-key map "\C-c\C-u" 'back-up-block)
    (define-key map "\C-c\C-@" 'mark-block)
    (define-key map "\C-c\C-n" 'narrow-to-block)
    (define-key map "\C-c~" 'self-assign-stmt)
    (define-key map "\C-c\[" 'open-comment-box)
    (define-key map "\C-c\C-m" 'continue-comment-box)
    (define-key map "\C-c\>" 'set-end-comment-col)
    (define-key map "\C-c}" 'pas-end-comment)
    (setq pas-mode-map map)))

(defvar pas-indent 2 "*This variable gives the indentation in Pascal-mode")

(defun pas-mode ()
"Mode to support program development in Pascal.
The prefix-key for pas-mode is Ctrl-C.

  TAB            pas-indent-line       Ctrl-c TAB     pas-tab-to-tab-col
  Ctrl-j         pas-newline           Ctrl-c b       pas-begin
  Ctrl-c Ctrl-f  forward-block         Ctrl-c Ctrl-b  backward-block
  Ctrl-c Ctrl-d  down-block            Ctrl-c Ctrl-u  back-up-block
  Ctrl-c Ctrl-e  up-block              Ctrl-c Ctrl-@  mark-block
  Ctrl-c Ctrl-n  narrow-to-block       Ctrl-c ~       self-assign-stmt
  Ctrl-c Ctrl-[  open-comment-box      Ctrl-c Ctrl-m  continue-comment-box
  Ctrl-c }       pas-end-comment       Ctrl-c >       set-end-comment-column

  pas-indent controls the number of spaces for each indentation."
  (interactive)
  (kill-all-local-variables)
  (use-local-map pas-mode-map)
  (setq major-mode 'pas-mode)
  (setq mode-name "Pascal")
  (setq local-abbrev-table pas-mode-abbrev-table)
  (make-local-variable 'comment-column)
  (setq comment-column 41)
  (make-local-variable 'box-com-col)
  (setq box-com-col 2)
  (make-local-variable 'end-comment-column)
  (setq end-comment-column 66)
  (set-syntax-table pas-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 'require-final-newline)
  (setq require-final-newline t)
  (make-local-variable 'comment-start)
  (setq comment-start "(*")
  (make-local-variable 'comment-end)
  (setq comment-end "*)")
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "(\\*+ *")
  (setq indent-tabs-mode nil)
  (make-local-variable 'pas-tab-col)
  (setq pas-tab-col 20)
  (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 'pas-mode-hook))


(defun pas-indent-line ()
  "Indent the current line based on the indentation of the
surrounding Pascal block, and on whether the previous line
ended a Pascal statement."
  (interactive)
  (let (blk-ind blk-beg prev-ind prev-beg shift-amt keep-going fishy)
    (save-excursion
      (beginning-of-line)
      (setq fishy (not (backward-scan-blocks 1 nil nil)))
      (beginning-of-line)
      (setq blk-beg (point))
      (setq blk-ind (current-indentation))
      (if fishy
        (setq indent (+ blk-ind pas-indent)) );; E-O-IF
      );; E-O-SAVE EXCURSION
    (if fishy nil
      (save-excursion
        (forward-line -1)
        (setq prev-beg (point))
        (setq prev-ind (current-indentation))
        (if (<= prev-beg blk-beg)       ; prev line is containing block
          (setq indent (+ blk-ind pas-indent))
          (skip-chars-forward " \t")
          (if (looking-at "\\<if\\>\\|\\<case\\>\\|\\<with\\>\\|\\<for\\>\\|\\<while\\>\\|\\<repeat\\>")
            (setq indent (+ prev-ind pas-indent)) ; then
            (setq indent (+ blk-ind pas-indent)) ; else
            (end-of-line)
            (if (or
                  (re-search-backward ";[ \t]*\\((\\*.*\\*)\\)*$" prev-beg t 1)
                  (re-search-backward "^ *(\\*.*\\*)$" prev-beg t 1)
                  (re-search-backward "^$" prev-beg t 1)
                  (= (point) prev-beg) )
              nil                       ; then block-indent will do
              (setq indent (+ prev-ind pas-indent)) ; else use previous-line indent
              )));; E-O-3 IFs
        ));; E-O-SAVE EXCURSION & IF
    (save-excursion
      (beginning-of-line)
      (setq prev-beg (point))
      (skip-chars-forward " \t")
      (if (and (not fishy) (looking-at "end\\|until"))
        (setq indent blk-ind)
        (save-excursion
          (cond ((looking-at "then")
                 (backward-find-kwd "\\<if\\>" nil)
                 (setq indent (+ (current-indentation) pas-indent)) )
                ((looking-at "else")
                 (setq then-cnt 1)
                 (setq keep-going t)
                 (while keep-going
                   (backward-find-kwd "\\<then\\>\\|\\<else\\>" nil)
                   (if (looking-at "then")
                       (setq then-cnt (1- then-cnt))
                     (setq then-cnt (1+ then-cnt)) )
                   (if (> then-cnt 0) nil
                     (setq keep-going nil)
                     (setq indent (current-indentation)) ));; E-O-WHILE
                 )
                (t nil) );; E-O-COND
          ));; E-O-SAVE EXCURSION & IF
      ;; install the right indentation
      (setq shift-amt (- indent (current-column)))
      (if (zerop shift-amt) nil
        (delete-region prev-beg (point))
        (indent-to indent) )
      );; E-O-SAVE EXCURSION
    (if (bolp) (back-to-indentation))
    ));; E-O-LET & PAS-INDENT-LINE

(defun pas-tab-to-tab-col (&optional arg)
  "Insert space to force indent to specified ARG column,
or to pas-tab-col."
  (interactive "P")
  (if arg
    (if (integerp arg)
      (setq pas-tab-col arg)            ; then
      (setq pas-tab-col (current-column)) ; else
      ))
  (indent-to pas-tab-col));; E-O-PAS TAB TO TAB-COL

(defun pas-newline ()
  "Insert a newline and indent it appropriately."
  (interactive)
  (newline)
  (pas-indent-line) );; E-O-PAS-NEWLINE

(defun pas-end-comment ()
  "Finish this comment correctly right-aligned."
  (interactive)
  (if (not (bolp))
      (indent-to end-comment-column 1))
  (insert "*)"))

(defun set-end-comment-column ()
  "Set the Pascal mode local variable end-comment-column
   to the column that point is on."
  (interactive)
  (message (concat "end-comment-column set to "
    (setq end-comment-column (current-column)) )))

(defun open-comment-box (arg)
  "Open a box comment: set box-com-col to the current
column.  Now, read the char to use for the comment line,
then insert two lines and open an aligned comment box."
  (interactive "cComment-line char: ")
  (setq box-com-col (current-column))
  (insert "(*")
  (let ( (counter 1)
         (lsize (- end-comment-column box-com-col)) )
    (while (< (setq counter (1+ counter)) lsize)
      (insert arg) )
    (insert "*)\n")
    (indent-to box-com-col 0)
    (insert "(*")
    (setq counter 1)
    (while (< (setq counter (1+ counter)) lsize)
      (insert arg) )
    (insert "*)")
    (beginning-of-line)
    (open-line 1)
    (indent-to box-com-col)
    (insert "(*  ") )                   ;; E-O-LET
  )   ;; E-O-OPEN-COMMENT-BOX


(defun continue-comment-box ()
  "Close current-line comment correctly right-aligned, open a new
indented comment on the next line, and indent to pas-tab-col."
  (interactive)
  (indent-to end-comment-column 1)
  (insert "*)\n")
  (indent-to box-com-col)
  (insert "(*")
  (indent-to pas-tab-col 2) )   ;; E-O-CONTINUE-COMMENT-BOX

(defun pas-begin (&optional arg)
  "Insert a 'begin' keyword & its comment at point, and
matching 'end'.  If ARG >= 1, insert the 'end' ARG lines
elow 'begin'.  If ARG < 0, insert 'end' at mark, and indent."
  (interactive "P")
  (let ((cmnt (read-string "Comment: "))
         (cur-pt 0)
         (cur-ind (current-indentation))
         (argval (if arg
                   (if (eq arg '-) -1 arg)
                   0)) )
    (insert "begin")
    (if (string-equal cmnt "") nil
      (setq cmnt (concat "   (* " cmnt " *)"))
      (insert cmnt) )                   ;; E-O-IF
    (setq cur-pt (point))
    (cond
      ((> argval 0)
        (next-line argval)
        (end-of-line) )
      ((< argval 0)
        (exchange-point-and-mark)
        (beginning-of-line)
        (backward-char 1) ))
    (newline)
    (indent-to cur-ind)
    (insert "end;")
    (if (string-equal cmnt "") nil
      (insert cmnt) )                   ;; E-O-IF
    (goto-char cur-pt)
    (if (= argval 0) (pas-newline))
    );; E-O-LET
  );; E-O-PAS BEGIN


(defun forward-find-kwd (target lim)
  "Leave point at the end of a keyword and return the position
of the beginning of the matched keyword, skipping comments
and literal strings en route.  If TARGET is specified, find it
outside comments & strings until limit LIM is reached.  If not
found, return NIL."
  (let ( (keep-looking t)
         (reg-str
           (concat (or target "\\<begin\\>\\|\\<end\\>\\|\\<record\\>\\|\\<case\\>\\|\\<repeat\\>\\|\\<until\\>")
             "\\|(\\*\\|{\\|""\\|'"))
         found mbeg mend next-target)
    (while keep-looking
      (setq found (re-search-forward reg-str lim t 1))
      (if (not found)
        ;;; then... didn't find any of the REG-STR components
        (setq keep-looking nil)
        ;;; else... goto beginning of match, check it out
        (setq mend (match-end 0))
        (goto-char (match-beginning 0))
        (setq mbeg (point))
        (cond
          ((and target (looking-at target))
            (setq keep-looking nil) )
          ((looking-at "(\\*") (setq next-target "*)"))
          ((looking-at "{") (setq next-target "}"))
          ((looking-at "'") (setq next-target "'"))
          ((looking-at """") (setq next-target """"))
          (t  (setq keep-looking nil)) );; E-O-COND
        (goto-char mend)
        (if keep-looking (search-forward next-target nil t 1)) );; E-O-OUTER IF
      )   ;; E-O-WHILE
    (and found mbeg)                    ; return-value = match-beginning
    );; E-O-LET
  );; E-O-FORWARD-FIND-KWD

(defun backward-find-kwd (target lim)
  "Leave point at the beginning of a keyword and return the
position of the end of the matched keyword, skipping comments
and literal strings en route.  If TARGET is specified, find it
outside comments & strings until limit LIM is reached.  If not
found, return NIL."
  (let ( (keep-looking t)
         (reg-str
           (concat (or target "\\<begin\\>\\|\\<end\\>\\|\\<record\\>\\|\\<case\\>\\|\\<repeat\\>\\|\\<until\\>")
             "\\|\\*)\\|}\\|""\\|'"))
         found mbeg mend next-target)
    (while keep-looking
      (setq found (re-search-backward reg-str lim t 1))
      (if (not found)
        ;;; then... didn't find any of the REG-STR components
        (setq keep-looking nil)
        ;;; else... we're at beginning of match, check it out
        (setq mend (match-end 0))
        (setq mbeg (point))
        (cond
          ((and target (looking-at target))
            (setq keep-looking nil) )
          ((looking-at "\\*)") (setq next-target "(*"))
          ((looking-at "}") (setq next-target "{"))
          ((looking-at "'") (setq next-target "'"))
          ((looking-at """") (setq next-target """"))
          (t  (setq keep-looking nil)) );; E-O-COND
        (if keep-looking (search-backward next-target nil t 1)) );; E-O-OUTER IF
      )   ;; E-O-WHILE
    (and found mend)                    ; return-value = match-end
    );; E-O-LET
  );; E-O-BACKWARD-FIND-KWD


(defun forward-scan-blocks (depth target lim)
  "Move forward:
   down into blocks if DEPTH < 0,
   across one block if DEPTH = 0,
   up out of blocks if DEPTH > 0.
Second arg TARGET = nil initially, used internally
to distinguish between until and end.
LIM bounds the search."
  (or target (setq target ""))
  (let (mbeg mend done fishy)
    (if (not (setq mbeg (forward-find-kwd nil lim)))
      (setq fishy t)                    ; bad location
      (setq mend (point))               ; else process kwd
      (goto-char mbeg)
      (cond
        ((looking-at "begin\\|case\\|record\\|repeat")
          (setq depth (1+ depth))
          (if (= depth 0) (setq done t)
            (if (looking-at "repeat")
              (setq target "until")     ; then
              (setq target "end") ))    ; else
          (goto-char mend) )
        ((looking-at "end\\|until")
          (if (<= depth 0)
            (setq fishy t)              ; bad location
            (setq depth (1- depth))     ; else...
            (if (and (= depth 0) (looking-at target))
              (setq done t) )
            (goto-char mend)
            (setq target nil) ))
        );; E-O-COND
      (if fishy nil                     ; return bad status
        (or done (forward-scan-blocks depth target lim)) ) ; else recurse
      );; E-O-MAIN IF
    );; E-O-LET
  );; E-O-FORWARD-SCAN-BLOCKS

(defun backward-scan-blocks (depth target lim)
  "Move backward:
   down into blocks if DEPTH < 0,
   across one block if DEPTH = 0,
   up out of blocks if DEPTH > 0.
Second arg TARGET = nil initially, used internally
to distinguish between until and end.
LIM bounds the search."
  (or target (setq target ""))
  (or lim (setq lim nil))
  (let (mend done fishy)
    (if (not (setq mend (backward-find-kwd nil lim)))
      (setq fishy t)                    ; bad location
      (cond                             ; else process kwd
        ((looking-at "end\\|until")
          (setq depth (1+ depth))
          (if (= depth 0) (setq done t)
            (if (looking-at "until")
              (setq target "repeat")    ; then
              (setq target "begin\\|case\\|record\\|repeat") ; else
              )))
        ((looking-at "begin\\|case\\|record\\|repeat")
          (if (<= depth 0)
            (setq fishy t)
            (setq depth (1- depth))
            (if (and (= depth 0) (looking-at target))
              (setq done t) )
            (setq target nil) ))
        );; E-O-COND
      (if fishy nil                     ; return bad status
        (or done (backward-scan-blocks depth target lim)) ) ; else recurse
      );; E-O-MAIN IF
    );; E-O-LET
  );; E-O-BACKWARD SCAN BLOCKS


(defun forward-block (&optional numblks)
  "Move forward across NUMBLKS balanced begin-end blocks."
  (interactive "p")
  (or numblks (setq numblks 1))
  (if (< numblks 0) (backward-block (- numblks))
    (let (found-pos fishy)
      (save-excursion
        (while (> numblks 0)
          (if (forward-scan-blocks 0 nil nil)
            (setq numblks (1- numblks)) ; then... all's well
            (setq fishy t)              ; else exit
            (setq numblks 0) )
          );; E-O-WHILE
        (setq found-pos (point)) );; E-O-SAVE-EXCURSION
      (if (not fishy)
        (goto-char found-pos)           ; happy ending
        (push-mark (point) t)           ; else mark and warn
        (goto-char found-pos)
        (send-string-to-terminal "")
        (message "Bad block structure, mark set.") )
      ));; E-O-LET & IF
  );; E-O-FORWARD-BLOCK

(defun backward-block (&optional numblks)
  "Move backward across NUMBLKS balanced begin-end block."
  (interactive "p")
  (or numblks (setq numblks 1))
  (if (< numblks 0) (forward-block (- numblks))
    (let (found-pos fishy)
      (save-excursion
        (while (> numblks 0)
          (if (backward-scan-blocks 0 nil nil)
            (setq numblks (1- numblks)) ; then... all's well
            (setq fishy t)              ; else exit
            (setq numblks 0) )
          );; E-O-WHILE
        (setq found-pos (point)) );; E-O-SAVE-EXCURSION
      (if (not fishy)
        (goto-char found-pos)           ; happy ending
        (push-mark (point) t)           ; else mark and warn
        (goto-char found-pos)
        (send-string-to-terminal "")
        (message "Bad block structure, mark set.") )
      ));; E-O-LET & IF
  );; E-O-BACKWARD-BLOCK

(defun down-block (&optional arg)
  "Move forward down ARG levels of begin-end block.
A negative argument means move backward but still down."
  (interactive "p")
  (or arg (setq arg 1))
  (let (found-pos all-swell)
    (save-excursion
      (setq all-swell
        (if (> arg 0)
          (forward-scan-blocks (- arg) nil nil) ; then
          (backward-scan-blocks arg nil nil) ; else
          ));; E-O-IF & SETQ
      (setq found-pos (point)) );; E-O-SAVE-EXCURSION
      (if all-swell
        (goto-char found-pos)           ; happy ending
        (push-mark (point) t)           ; else mark and warn
        (goto-char found-pos)
        (send-string-to-terminal "")
        (message "Bad block structure, mark set.") );; E-O-IF
    );; E-O-LET
  );; E-O-DOWN-BLOCK

(defun back-up-block (&optional arg)
  "Move backward out of ARG levels of begin-end blocks.
   A negative argument means move forward but still up."
  (interactive "p")
  (or arg (setq arg 1))
  (up-block (- arg)))

(defun up-block (&optional arg)
  "Move forward out of ARG levels of begin-end blocks.
   A negative argument means move backward but still up."
  (interactive "p")
  (or arg (setq arg 1))
  (let (found-pos all-swell)
    (save-excursion
      (setq all-swell
        (if (> arg 0)
          (forward-scan-blocks arg nil nil) ; then
          (backward-scan-blocks (- arg) nil nil)
          ));; E-O-IF & SETQ
      (setq found-pos (point)) );; E-O-SAVE-EXCURSION
      (if all-swell
        (goto-char found-pos)           ; happy ending
        (push-mark (point) t)           ; else mark and warn
        (goto-char found-pos)
        (send-string-to-terminal "")
        (message "Bad block structure, mark set.") );; E-O-IF
    );; E-O-LET
  );; E-O-UP-BLOCK


(defun mark-block (&optional arg)
  "Set mark at the end of the next block from point.
With argument, do this that many blocks away.  Leave
the cursor at top-of-region."
  (interactive "p")
  (or arg (setq arg 1))
  (let (save-loc all-swell)
    (save-excursion
      (setq all-swell
            (forward-block arg))
      (end-of-line)
      (setq save-loc (point)) );; E-O-IF & SAVE-EXCURSION
    (push-mark save-loc 1)
    (if all-swell
        (message "Block marked.")
      (send-string-to-terminal "")
      (message "Bad block structure, mark set.") )
    );; E-O-LET
  );;E-O-MARK-BLOCK

(defun narrow-to-block (&optional arg)
  "Narrow window down to the next block ahead from the cursor.
   With argument, do this that many blocks ahead (or back)."
  (interactive "p")
  (or arg (setq arg 1))
  (let ( (reg-beg (point))
         (reg-end 0)
         all-swell)
    (save-excursion
      (cond
        ((< arg 0)
          (setq all-swell (backward-block (- arg)))
          (beginning-of-line)
          (setq reg-end (point)) )
        (t
          (setq all-swell (forward-block arg))
          (end-of-line)
          (setq reg-end (point)) ));; E-O-COND
      );; E-O-SAVE-EXCURSION
    (cond
      (all-swell
        (narrow-to-region reg-beg reg-end)
        (goto-char (min reg-beg reg-end)) )
      (t
        (push-mark reg-end)
        (send-string-to-terminal "")
        (message "Bad block structure, mark set.") )
      );; E-O-COND
    );; E-O-LET
  );; E-O-NARROW-TO-BLOCK

(defun self-assign-stmt ()
  "Given variable X typed in, generate X := X."
  (interactive)
  (let (cur-pt var-end tmpstr)
    (setq cur-pt (point))
    (skip-chars-backward " \t")
    (setq var-end (point))
    (skip-chars-backward "^ \t\n")
    (setq tmpstr (buffer-substring (point) var-end))
    (goto-char cur-pt)
    (insert " := " tmpstr " ") ))

mdt@s1.sys.uea.ac.uk (M.D. Templeton GEC ) (10/21/88)

It's all very well posting bits of lisp code to create new modes, and so on,
but how do I autoload it??? Especially if the code is compiled, then I can't
just put it in my .emacs file, and I can't get the hang of using autoload
in .emacs, myself. Can someone tell me how to do it??

By the way, our manual doesn't seem to tell me - we have only the online
manual, and, until I find someone with newer emacs source, I have only
emacs version 17.64.

Looking forward to enlightenment....

			The Druid.

I don't know if this mailer will add the header.. I'm mdt@uk.ac.uea.sys
or the other way round.. You know which order to write the address?

spolsky@cs.yale.edu (Joel Spolsky) (10/24/88)

In article <169@s1.sys.uea.ac.uk>, mdt@s1 (M.D. Templeton GEC ) writes:
| It's all very well posting bits of lisp code to create new modes, and so on,
| but how do I autoload it??? Especially if the code is compiled, then I can't
| just put it in my .emacs file, and I can't get the hang of using autoload
| in .emacs, myself. Can someone tell me how to do it??


OK. Let's say you have a function named "make-coffee" in the file 
"/emacs/lisp/extended_functions.el". All you do is put the command

(autoload 'make-coffee 
	  "/emacs/lisp/extended_functions" 
	  "Make a nice pot of coffee" 
	  t)

in your .emacs file. Now the function make-coffee is available, emacs
can even auto-expand it, and when you call it, the file specified will
be loaded.

+----------------+---------------------------------------------------+
|  Joel Spolsky  | bitnet: spolsky@yalecs     uucp: ...!yale!spolsky |
|                | arpa:   spolsky@yale.edu   voicenet: 203-436-1483 |
+----------------+---------------------------------------------------+
                                               #include <disclaimer.h>

mosurm@mntgfx.mentor.com (Mosur Mohan) (10/26/88)

In article <169@s1.sys.uea.ac.uk>, mdt@s1.sys.uea.ac.uk (M.D. Templeton GEC ) writes:
> It's all very well posting bits of lisp code to create new modes, and so on,
> but how do I autoload it?...
> 
> 			The Druid.

Here's the relevant snippet from my .emacs:

;; auto-mode-alist is the association-list that tells Emacs
;; how to determine the right mode based on the file-extension
;; This example identifies .pas, .inc, .pai and .p files as Pascal files
(setq auto-mode-alist
  (append auto-mode-alist
    '(("\\.pas$" . pas-mode)
      ("\\.inc$" . pas-mode)
      ("\\.pai$" . pas-mode)
      ("\\.p$" . pas-mode)) ))

;; This tells Emacs where to go to find the pas-mode code.
;; Emacs automatically looks for a pas-mode.elc, then a .el file
(autoload 'pas-mode "/user/mosurm/code/emacs/pas-mode"
  "This is a mode intended to support program development in Pascal.
Control-C is the prefix to reach functions special to pas-mode." t)

-- 
-- Mohan.   {uunet!mntgfx!mosurm}
            {Mosur Mohan, Mentor Graphics, Beaverton, OR}