1;;; modula2.el --- Modula-2 editing support package 2 3;; Author: Michael Schmidt <michael@pbinfo.UUCP> 4;; Tom Perrine <Perrin@LOGICON.ARPA> 5;; Keywords: languages 6 7;; The authors distributed this without a copyright notice 8;; back in 1988, so it is in the public domain. The original included 9;; the following credit: 10 11;; Author Mick Jordan 12;; amended Peter Robinson 13 14;;; Commentary: 15 16;; A major mode for editing Modula-2 code. It provides convenient abbrevs 17;; for Modula-2 keywords, knows about the standard layout rules, and supports 18;; a native compile command. 19 20;;; Code: 21 22;;; Added by Tom Perrine (TEP) 23(defvar m2-mode-syntax-table nil 24 "Syntax table in use in Modula-2 buffers.") 25 26(defvar m2-compile-command "m2c" 27 "Command to compile Modula-2 programs") 28 29(defvar m2-link-command "m2l" 30 "Command to link Modula-2 programs") 31 32(defvar m2-link-name nil 33 "Name of the executable.") 34 35 36(if m2-mode-syntax-table 37 () 38 (let ((table (make-syntax-table))) 39 (modify-syntax-entry ?\\ "\\" table) 40 (modify-syntax-entry ?\( ". 1" table) 41 (modify-syntax-entry ?\) ". 4" table) 42 (modify-syntax-entry ?* ". 23" table) 43 (modify-syntax-entry ?+ "." table) 44 (modify-syntax-entry ?- "." table) 45 (modify-syntax-entry ?= "." table) 46 (modify-syntax-entry ?% "." table) 47 (modify-syntax-entry ?< "." table) 48 (modify-syntax-entry ?> "." table) 49 (modify-syntax-entry ?\' "\"" table) 50 (setq m2-mode-syntax-table table))) 51 52;;; Added by TEP 53(defvar m2-mode-map nil 54 "Keymap used in Modula-2 mode.") 55 56(if m2-mode-map () 57 (let ((map (make-sparse-keymap))) 58 (define-key map "\^i" 'm2-tab) 59 (define-key map "\C-cb" 'm2-begin) 60 (define-key map "\C-cc" 'm2-case) 61 (define-key map "\C-cd" 'm2-definition) 62 (define-key map "\C-ce" 'm2-else) 63 (define-key map "\C-cf" 'm2-for) 64 (define-key map "\C-ch" 'm2-header) 65 (define-key map "\C-ci" 'm2-if) 66 (define-key map "\C-cm" 'm2-module) 67 (define-key map "\C-cl" 'm2-loop) 68 (define-key map "\C-co" 'm2-or) 69 (define-key map "\C-cp" 'm2-procedure) 70 (define-key map "\C-c\C-w" 'm2-with) 71 (define-key map "\C-cr" 'm2-record) 72 (define-key map "\C-cs" 'm2-stdio) 73 (define-key map "\C-ct" 'm2-type) 74 (define-key map "\C-cu" 'm2-until) 75 (define-key map "\C-cv" 'm2-var) 76 (define-key map "\C-cw" 'm2-while) 77 (define-key map "\C-cx" 'm2-export) 78 (define-key map "\C-cy" 'm2-import) 79 (define-key map "\C-c{" 'm2-begin-comment) 80 (define-key map "\C-c}" 'm2-end-comment) 81 (define-key map "\C-j" 'm2-newline) 82 (define-key map "\C-c\C-z" 'suspend-emacs) 83 (define-key map "\C-c\C-v" 'm2-visit) 84 (define-key map "\C-c\C-t" 'm2-toggle) 85 (define-key map "\C-c\C-l" 'm2-link) 86 (define-key map "\C-c\C-c" 'm2-compile) 87 (setq m2-mode-map map))) 88 89(defvar m2-indent 5 "*This variable gives the indentation in Modula-2-Mode") 90 91;;;###autoload 92(defun modula-2-mode () 93 "This is a mode intended to support program development in Modula-2. 94All control constructs of Modula-2 can be reached by typing C-c 95followed by the first character of the construct. 96\\<m2-mode-map> 97 \\[m2-begin] begin \\[m2-case] case 98 \\[m2-definition] definition \\[m2-else] else 99 \\[m2-for] for \\[m2-header] header 100 \\[m2-if] if \\[m2-module] module 101 \\[m2-loop] loop \\[m2-or] or 102 \\[m2-procedure] procedure Control-c Control-w with 103 \\[m2-record] record \\[m2-stdio] stdio 104 \\[m2-type] type \\[m2-until] until 105 \\[m2-var] var \\[m2-while] while 106 \\[m2-export] export \\[m2-import] import 107 \\[m2-begin-comment] begin-comment \\[m2-end-comment] end-comment 108 \\[suspend-emacs] suspend Emacs \\[m2-toggle] toggle 109 \\[m2-compile] compile \\[m2-next-error] next-error 110 \\[m2-link] link 111 112 `m2-indent' controls the number of spaces for each indentation. 113 `m2-compile-command' holds the command to compile a Modula-2 program. 114 `m2-link-command' holds the command to link a Modula-2 program." 115 (interactive) 116 (kill-all-local-variables) 117 (use-local-map m2-mode-map) 118 (setq major-mode 'modula-2-mode) 119 (setq mode-name "Modula-2") 120 (make-local-variable 'comment-column) 121 (setq comment-column 41) 122 (make-local-variable 'end-comment-column) 123 (setq end-comment-column 75) 124 (set-syntax-table m2-mode-syntax-table) 125 (make-local-variable 'paragraph-start) 126 (setq paragraph-start (concat "^$\\|" page-delimiter)) 127 (make-local-variable 'paragraph-separate) 128 (setq paragraph-separate paragraph-start) 129 (make-local-variable 'paragraph-ignore-fill-prefix) 130 (setq paragraph-ignore-fill-prefix t) 131; (make-local-variable 'indent-line-function) 132; (setq indent-line-function 'c-indent-line) 133 (make-local-variable 'require-final-newline) 134 (setq require-final-newline t) 135 (make-local-variable 'comment-start) 136 (setq comment-start "(* ") 137 (make-local-variable 'comment-end) 138 (setq comment-end " *)") 139 (make-local-variable 'comment-column) 140 (setq comment-column 41) 141 (make-local-variable 'comment-start-skip) 142 (setq comment-start-skip "/\\*+ *") 143 (make-local-variable 'comment-indent-function) 144 (setq comment-indent-function 'c-comment-indent) 145 (make-local-variable 'parse-sexp-ignore-comments) 146 (setq parse-sexp-ignore-comments t) 147 (run-hooks 'm2-mode-hook)) 148 149(defun m2-newline () 150 "Insert a newline and indent following line like previous line." 151 (interactive) 152 (let ((hpos (current-indentation))) 153 (newline) 154 (indent-to hpos))) 155 156(defun m2-tab () 157 "Indent to next tab stop." 158 (interactive) 159 (indent-to (* (1+ (/ (current-indentation) m2-indent)) m2-indent))) 160 161(defun m2-begin () 162 "Insert a BEGIN keyword and indent for the next line." 163 (interactive) 164 (insert "BEGIN") 165 (m2-newline) 166 (m2-tab)) 167 168(defun m2-case () 169 "Build skeleton CASE statment, prompting for the <expression>." 170 (interactive) 171 (let ((name (read-string "Case-Expression: "))) 172 (insert "CASE " name " OF") 173 (m2-newline) 174 (m2-newline) 175 (insert "END (* case " name " *);")) 176 (end-of-line 0) 177 (m2-tab)) 178 179(defun m2-definition () 180 "Build skeleton DEFINITION MODULE, prompting for the <module name>." 181 (interactive) 182 (insert "DEFINITION MODULE ") 183 (let ((name (read-string "Name: "))) 184 (insert name ";\n\n\n\nEND " name ".\n")) 185 (previous-line 3)) 186 187(defun m2-else () 188 "Insert ELSE keyword and indent for next line." 189 (interactive) 190 (m2-newline) 191 (backward-delete-char-untabify m2-indent ()) 192 (insert "ELSE") 193 (m2-newline) 194 (m2-tab)) 195 196(defun m2-for () 197 "Build skeleton FOR loop statment, prompting for the loop parameters." 198 (interactive) 199 (insert "FOR ") 200 (let ((name (read-string "Loop Initialiser: ")) limit by) 201 (insert name " TO ") 202 (setq limit (read-string "Limit: ")) 203 (insert limit) 204 (setq by (read-string "Step: ")) 205 (if (not (string-equal by "")) 206 (insert " BY " by)) 207 (insert " DO") 208 (m2-newline) 209 (m2-newline) 210 (insert "END (* for " name " to " limit " *);")) 211 (end-of-line 0) 212 (m2-tab)) 213 214(defun m2-header () 215 "Insert a comment block containing the module title, author, etc." 216 (interactive) 217 (insert "(*\n Title: \t") 218 (insert (read-string "Title: ")) 219 (insert "\n Created:\t") 220 (insert (current-time-string)) 221 (insert "\n Author: \t") 222 (insert (user-full-name)) 223 (insert (concat "\n\t\t<" (user-login-name) "@" (system-name) ">\n")) 224 (insert "*)\n\n")) 225 226(defun m2-if () 227 "Insert skeleton IF statment, prompting for <boolean-expression>." 228 (interactive) 229 (insert "IF ") 230 (let ((thecondition (read-string "<boolean-expression>: "))) 231 (insert thecondition " THEN") 232 (m2-newline) 233 (m2-newline) 234 (insert "END (* if " thecondition " *);")) 235 (end-of-line 0) 236 (m2-tab)) 237 238(defun m2-loop () 239 "Build skeleton LOOP (with END)." 240 (interactive) 241 (insert "LOOP") 242 (m2-newline) 243 (m2-newline) 244 (insert "END (* loop *);") 245 (end-of-line 0) 246 (m2-tab)) 247 248(defun m2-module () 249 "Build skeleton IMPLEMENTATION MODULE, prompting for <module-name>." 250 (interactive) 251 (insert "IMPLEMENTATION MODULE ") 252 (let ((name (read-string "Name: "))) 253 (insert name ";\n\n\n\nEND " name ".\n") 254 (previous-line 3) 255 (m2-header) 256 (m2-type) 257 (newline) 258 (m2-var) 259 (newline) 260 (m2-begin) 261 (m2-begin-comment) 262 (insert " Module " name " Initialisation Code ")) 263 (m2-end-comment) 264 (newline) 265 (m2-tab)) 266 267(defun m2-or () 268 (interactive) 269 (m2-newline) 270 (backward-delete-char-untabify m2-indent) 271 (insert "|") 272 (m2-newline) 273 (m2-tab)) 274 275(defun m2-procedure () 276 (interactive) 277 (insert "PROCEDURE ") 278 (let ((name (read-string "Name: " )) 279 args) 280 (insert name " (") 281 (insert (read-string "Arguments: ") ")") 282 (setq args (read-string "Result Type: ")) 283 (if (not (string-equal args "")) 284 (insert " : " args)) 285 (insert ";") 286 (m2-newline) 287 (insert "BEGIN") 288 (m2-newline) 289 (m2-newline) 290 (insert "END ") 291 (insert name) 292 (insert ";") 293 (end-of-line 0) 294 (m2-tab))) 295 296(defun m2-with () 297 (interactive) 298 (insert "WITH ") 299 (let ((name (read-string "Record-Type: "))) 300 (insert name) 301 (insert " DO") 302 (m2-newline) 303 (m2-newline) 304 (insert "END (* with " name " *);")) 305 (end-of-line 0) 306 (m2-tab)) 307 308(defun m2-record () 309 (interactive) 310 (insert "RECORD") 311 (m2-newline) 312 (m2-newline) 313 (insert "END (* record *);") 314 (end-of-line 0) 315 (m2-tab)) 316 317(defun m2-stdio () 318 (interactive) 319 (insert " 320FROM TextIO IMPORT 321 WriteCHAR, ReadCHAR, WriteINTEGER, ReadINTEGER, 322 WriteCARDINAL, ReadCARDINAL, WriteBOOLEAN, ReadBOOLEAN, 323 WriteREAL, ReadREAL, WriteBITSET, ReadBITSET, 324 WriteBasedCARDINAL, ReadBasedCARDINAL, WriteChars, ReadChars, 325 WriteString, ReadString, WhiteSpace, EndOfLine; 326 327FROM SysStreams IMPORT sysIn, sysOut, sysErr; 328 329")) 330 331(defun m2-type () 332 (interactive) 333 (insert "TYPE") 334 (m2-newline) 335 (m2-tab)) 336 337(defun m2-until () 338 (interactive) 339 (insert "REPEAT") 340 (m2-newline) 341 (m2-newline) 342 (insert "UNTIL ") 343 (insert (read-string "<boolean-expression>: ") ";") 344 (end-of-line 0) 345 (m2-tab)) 346 347(defun m2-var () 348 (interactive) 349 (m2-newline) 350 (insert "VAR") 351 (m2-newline) 352 (m2-tab)) 353 354(defun m2-while () 355 (interactive) 356 (insert "WHILE ") 357 (let ((name (read-string "<boolean-expression>: "))) 358 (insert name " DO" ) 359 (m2-newline) 360 (m2-newline) 361 (insert "END (* while " name " *);")) 362 (end-of-line 0) 363 (m2-tab)) 364 365(defun m2-export () 366 (interactive) 367 (insert "EXPORT QUALIFIED ")) 368 369(defun m2-import () 370 (interactive) 371 (insert "FROM ") 372 (insert (read-string "Module: ")) 373 (insert " IMPORT ")) 374 375(defun m2-begin-comment () 376 (interactive) 377 (if (not (bolp)) 378 (indent-to comment-column 0)) 379 (insert "(* ")) 380 381(defun m2-end-comment () 382 (interactive) 383 (if (not (bolp)) 384 (indent-to end-comment-column)) 385 (insert "*)")) 386 387(defun m2-compile () 388 (interactive) 389 (setq modulename (buffer-name)) 390 (compile (concat m2-compile-command " " modulename))) 391 392(defun m2-link () 393 (interactive) 394 (setq modulename (buffer-name)) 395 (if m2-link-name 396 (compile (concat m2-link-command " " m2-link-name)) 397 (compile (concat m2-link-command " " 398 (setq m2-link-name (read-string "Name of executable: " 399 modulename)))))) 400 401(defun execute-monitor-command (command) 402 (let* ((shell shell-file-name) 403 (csh (equal (file-name-nondirectory shell) "csh"))) 404 (call-process shell nil t t "-cf" (concat "exec " command)))) 405 406(defun m2-visit () 407 (interactive) 408 (let ((deffile nil) 409 (modfile nil) 410 modulename) 411 (save-excursion 412 (setq modulename 413 (read-string "Module name: ")) 414 (switch-to-buffer "*Command Execution*") 415 (execute-monitor-command (concat "m2whereis " modulename)) 416 (goto-char (point-min)) 417 (condition-case () 418 (progn (re-search-forward "\\(.*\\.def\\) *$") 419 (setq deffile (buffer-substring (match-beginning 1) 420 (match-end 1)))) 421 (search-failed ())) 422 (condition-case () 423 (progn (re-search-forward "\\(.*\\.mod\\) *$") 424 (setq modfile (buffer-substring (match-beginning 1) 425 (match-end 1)))) 426 (search-failed ())) 427 (if (not (or deffile modfile)) 428 (error "I can find neither definition nor implementation of %s" 429 modulename))) 430 (cond (deffile 431 (find-file deffile) 432 (if modfile 433 (save-excursion 434 (find-file modfile)))) 435 (modfile 436 (find-file modfile))))) 437 438(defun m2-toggle () 439 "Toggle between .mod and .def files for the module." 440 (interactive) 441 (cond ((string-equal (substring (buffer-name) -4) ".def") 442 (find-file-other-window 443 (concat (substring (buffer-name) 0 -4) ".mod"))) 444 ((string-equal (substring (buffer-name) -4) ".mod") 445 (find-file-other-window 446 (concat (substring (buffer-name) 0 -4) ".def"))) 447 ((string-equal (substring (buffer-name) -3) ".mi") 448 (find-file-other-window 449 (concat (substring (buffer-name) 0 -3) ".md"))) 450 ((string-equal (substring (buffer-name) -3) ".md") 451 (find-file-other-window 452 (concat (substring (buffer-name) 0 -3) ".mi"))))) 453 454;;; modula2.el ends here 455