remove empty dir
[ghc-hetmet.git] / ghc / rts / gmp / mpn / lisp / gmpasm-mode.el
1 ;;; gmpasm-mode.el -- GNU MP asm and m4 editing mode.
2
3
4 ;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
5 ;;
6 ;; This file is part of the GNU MP Library.
7 ;;
8 ;; The GNU MP Library is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU Lesser General Public License as published by
10 ;; the Free Software Foundation; either version 2.1 of the License, or (at your
11 ;; option) any later version.
12 ;;
13 ;; The GNU MP Library is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 ;; License for more details.
17 ;;
18 ;; You should have received a copy of the GNU Lesser General Public License
19 ;; along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
20 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 ;; MA 02111-1307, USA.
22
23
24 ;;; Commentary:
25 ;;
26 ;; gmpasm-mode is an editing mode for m4 processed assembler code and m4
27 ;; macro files in GMP.  It's similar to m4-mode, but has a number of
28 ;; settings better suited to GMP.
29 ;;
30 ;;
31 ;; Install
32 ;; -------
33 ;;
34 ;; To make M-x gmpasm-mode available, put gmpasm-mode.el somewhere in the
35 ;; load-path and the following in .emacs
36 ;;
37 ;;      (autoload 'gmpasm-mode "gmpasm-mode" nil t)
38 ;;
39 ;; To use gmpasm-mode automatically on all .asm and .m4 files, put the
40 ;; following in .emacs
41 ;;
42 ;;      (add-to-list 'auto-mode-alist '("\\.asm\\'" . gmpasm-mode))
43 ;;      (add-to-list 'auto-mode-alist '("\\.m4\\'" . gmpasm-mode))
44 ;;
45 ;; To have gmpasm-mode only on gmp files, try instead something like the
46 ;; following, which uses it only in a directory starting with "gmp", or a
47 ;; sub-directory of such.
48 ;;
49 ;;      (add-to-list 'auto-mode-alist
50 ;;                   '("/gmp.*/.*\\.\\(asm\\|m4\\)\\'" . gmpasm-mode))
51 ;;
52 ;; Byte compiling will slightly speed up loading.  If you want a docstring
53 ;; in the autoload you can use M-x update-file-autoloads if you set it up
54 ;; right.
55 ;;
56 ;;
57 ;; Emacsen
58 ;; -------
59 ;;
60 ;; FSF Emacs 20.x - gmpasm-mode is designed for this.
61 ;; XEmacs 20.x - seems to work.
62 ;;
63 ;; FSF Emacs 19.x - should work if replacements for some 20.x-isms are
64 ;;    available.  comment-region with "C" won't really do the right thing
65 ;;    though.
66
67
68 ;;; Code:
69
70 (defgroup gmpasm nil
71   "GNU MP m4 and asm editing."
72   :prefix "gmpasm-"
73   :group 'languages)
74
75 (defcustom gmpasm-mode-hook nil
76   "*Hook called by `gmpasm-mode'."
77   :type 'hook
78   :group 'gmpasm)
79
80 (defcustom gmpasm-comment-start-regexp "[#;!@C]"
81   "*Regexp matching possible comment styles.
82 See `gmpasm-mode' docstring for how this is used."
83   :type 'regexp
84   :group 'gmpasm)
85
86
87 (defun gmpasm-add-to-list-second (list-var element)
88   "(gmpasm-add-to-list-second LIST-VAR ELEMENT)
89
90 Add ELEMENT to LIST-VAR as the second element in the list, if it isn't
91 already in the list.  If LIST-VAR is nil, then ELEMENT is just added as the
92 sole element in the list.
93
94 This is like `add-to-list', but it puts the new value second in the list.
95
96 The first cons cell is copied rather than changed in-place, so references to
97 the list elsewhere won't be affected."
98
99   (if (member element (symbol-value list-var))
100       (symbol-value list-var)
101     (set list-var
102          (if (symbol-value list-var)
103              (cons (car (symbol-value list-var))
104                    (cons element
105                          (cdr (symbol-value list-var))))
106            (list element)))))
107
108
109 (defun gmpasm-delete-from-list (list-var element)
110   "(gmpasm-delete-from-list LIST-VAR ELEMENT)
111
112 Delete ELEMENT from LIST-VAR, using `delete'.
113 This is like `add-to-list', but the element is deleted from the list.
114 The list is copied rather than changed in-place, so references to it elsewhere
115 won't be affected."
116
117   (set list-var (delete element (copy-sequence (symbol-value list-var)))))
118
119
120 (defvar gmpasm-mode-map
121   (let ((map (make-sparse-keymap)))
122     
123     ;; assembler and dnl commenting
124     (define-key map "\C-c\C-c" 'comment-region)
125     (define-key map "\C-c\C-d" 'gmpasm-comment-region-dnl)
126     
127     ;; kill an M-x compile, since it's not hard to put m4 into an infinite
128     ;; loop
129     (define-key map "\C-c\C-k" 'kill-compilation)
130     
131     map)
132   "Keymap for `gmpasm-mode'.")
133
134
135 (defvar gmpasm-mode-syntax-table
136   (let ((table (make-syntax-table)))
137     ;; underscore left as a symbol char, like C mode
138     
139     ;; m4 quotes
140     (modify-syntax-entry ?`  "('"  table)
141     (modify-syntax-entry ?'  ")`"  table)
142
143     table)
144   "Syntax table used in `gmpasm-mode'.
145
146 m4 ignores quote marks in # comments at the top level, but inside quotes #
147 isn't special and all quotes are active.  There seems no easy way to express
148 this in the syntax table, so nothing is done for comments.  Usually this is
149 best, since it picks up invalid apostrophes in comments inside quotes.")
150
151
152 (defvar gmpasm-font-lock-keywords
153   (eval-when-compile
154     (list
155      (cons
156       (concat
157        "\\b"
158        (regexp-opt
159         '("deflit" "defreg" "defframe" "defframe_pushl"
160           "define_not_for_expansion"
161           "ASM_START" "ASM_END" "PROLOGUE" "EPILOGUE"
162           "forloop"
163           "TEXT" "DATA" "ALIGN" "W32"
164           "builtin" "changecom" "changequote" "changeword" "debugfile"
165           "debugmode" "decr" "define" "defn" "divert" "divnum" "dumpdef"
166           "errprint" "esyscmd" "eval" "__file__" "format" "gnu" "ifdef"
167           "ifelse" "include" "incr" "index" "indir" "len" "__line__"
168           "m4exit" "m4wrap" "maketemp" "patsubst" "popdef" "pushdef"
169           "regexp" "shift" "sinclude" "substr" "syscmd" "sysval"
170           "traceoff" "traceon" "translit" "undefine" "undivert" "unix")
171         t)
172        "\\b") 'font-lock-keyword-face)))
173
174   "`font-lock-keywords' for `gmpasm-mode'.
175
176 The keywords are m4 builtins and some of the GMP macros used in asm files.
177 L and LF don't look good fontified, so they're omitted.
178
179 The right assembler comment regexp is added dynamically buffer-local (with
180 dnl too).")
181
182
183 ;; Initialized if gmpasm-mode finds filladapt loaded.
184 (defvar gmpasm-filladapt-token-table nil
185   "Filladapt token table used in `gmpasm-mode'.")
186 (defvar gmpasm-filladapt-token-match-table nil
187   "Filladapt token match table used in `gmpasm-mode'.")
188 (defvar gmpasm-filladapt-token-conversion-table nil
189   "Filladapt token conversion table used in `gmpasm-mode'.")
190
191
192 ;;;###autoload
193 (defun gmpasm-mode ()
194   "A major mode for editing GNU MP asm and m4 files.
195
196 \\{gmpasm-mode-map}
197 `comment-start' and `comment-end' are set buffer-local to assembler
198 commenting appropriate for the CPU by looking for something matching
199 `gmpasm-comment-start-regexp' at the start of a line, or \"#\" is used if
200 there's no match (if \"#\" isn't what you want, type in a desired comment
201 and do \\[gmpasm-mode] to reinitialize).
202
203 `adaptive-fill-regexp' is set buffer-local to the standard regexp with
204 `comment-start' and dnl added.  If filladapt.el has been loaded it similarly
205 gets `comment-start' and dnl added as buffer-local fill prefixes.
206
207 Font locking has the m4 builtins, some of the GMP macros, m4 dnl commenting,
208 and assembler commenting (based on the `comment-start' determined).
209
210 Note that `gmpasm-comment-start-regexp' is only matched as a whole word, so
211 the `C' in it is only matched as a whole word, not on something that happens
212 to start with `C'.  Also it's only the particular `comment-start' determined
213 that's added for filling etc, not the whole `gmpasm-comment-start-regexp'.
214
215 `gmpasm-mode-hook' is run after initializations are complete.
216 "
217
218   (interactive)
219   (kill-all-local-variables)
220   (setq major-mode 'gmpasm-mode
221         mode-name  "gmpasm")
222   (use-local-map gmpasm-mode-map)
223   (set-syntax-table gmpasm-mode-syntax-table)
224   (setq fill-column 76)
225
226   ;; Short instructions might fit with 32, but anything with labels or
227   ;; expressions soon needs the comments pushed out to column 40.
228   (setq comment-column 40)
229
230   ;; Don't want to find out the hard way which dumb assemblers don't like a
231   ;; missing final newline.
232   (set (make-local-variable 'require-final-newline) t)
233
234   ;; The first match of gmpasm-comment-start-regexp at the start of a line
235   ;; determines comment-start, or "#" if no match.
236   (set (make-local-variable 'comment-start)
237        (save-excursion
238          (goto-char (point-min))
239          (if (re-search-forward
240               (concat "^\\(" gmpasm-comment-start-regexp "\\)\\(\\s-\\|$\\)")
241               nil t)
242              (match-string 1)
243            "#")))
244   (set (make-local-variable 'comment-end) "")
245
246   ;; If comment-start ends in an alphanumeric then \b is used to match it
247   ;; only as a separate word.  The test is for an alphanumeric rather than
248   ;; \w since we might try # or ! as \w characters but without wanting \b.
249   (let ((comment-regexp
250          (concat (regexp-quote comment-start)
251                  (if (string-match "[a-zA-Z0-9]\\'" comment-start) "\\b"))))
252     
253     ;; Whitespace is required before a comment-start so m4 $# doesn't match
254     ;; when comment-start is "#".
255     ;; Only spaces or tabs match after, so newline isn't included in the
256     ;; font lock below.
257     (set (make-local-variable 'comment-start-skip)
258          (concat "\\(^\\|\\s-\\)" comment-regexp "[ \t]*"))
259
260     ;; Comment fontification based on comment-start, matching through to the
261     ;; end of the line.
262     (add-to-list (make-local-variable 'gmpasm-font-lock-keywords)
263                  (cons (concat
264                         "\\(\\bdnl\\b\\|" comment-start-skip "\\).*$")
265                        'font-lock-comment-face))
266
267     (set (make-local-variable 'font-lock-defaults)
268          '(gmpasm-font-lock-keywords
269            t             ; no syntactic fontification (of strings etc)
270            nil           ; no case-fold
271            ((?_ . "w"))  ; _ part of a word while fontifying
272            ))
273
274     ;; Paragraphs are separated by blank lines, or lines with only dnl or
275     ;; comment-start.
276     (set (make-local-variable 'paragraph-separate)
277          (concat "[ \t\f]*\\(\\(" comment-regexp "\\|dnl\\)[ \t]*\\)*$"))
278     (set (make-local-variable 'paragraph-start)
279          (concat "\f\\|" paragraph-separate))
280  
281     ;; Adaptive fill gets dnl and comment-start as comment style prefixes on
282     ;; top of the standard regexp (which has # and ; already actually).
283     (set (make-local-variable 'adaptive-fill-regexp)
284          (concat "[ \t]*\\(\\("
285                  comment-regexp
286                  "\\|dnl\\|[-|#;>*]+\\|(?[0-9]+[.)]\\)[ \t]*\\)*"))
287     (set (make-local-variable 'adaptive-fill-first-line-regexp)
288          "\\`\\([ \t]*dnl\\)?[ \t]*\\'")
289
290     (when (fboundp 'filladapt-mode)
291       (when (not gmpasm-filladapt-token-table)
292         (setq gmpasm-filladapt-token-table
293               filladapt-token-table)
294         (setq gmpasm-filladapt-token-match-table
295               filladapt-token-match-table)
296         (setq gmpasm-filladapt-token-conversion-table
297               filladapt-token-conversion-table)
298         
299         ;; Numbered bullet points like "2.1" get matched at the start of a
300         ;; line when it's really something like "2.1 cycles/limb", so delete
301         ;; this from the list.  The regexp for "1.", "2." etc is left
302         ;; though.
303         (gmpasm-delete-from-list 'gmpasm-filladapt-token-table
304                                  '("[0-9]+\\(\\.[0-9]+\\)+[ \t]"
305                                    bullet))
306           
307         ;; "%" as a comment prefix interferes with x86 register names
308         ;; like %eax, so delete this.
309         (gmpasm-delete-from-list 'gmpasm-filladapt-token-table
310                                  '("%+" postscript-comment))
311         
312         (add-to-list 'gmpasm-filladapt-token-match-table
313                      '(gmpasm-comment gmpasm-comment))
314         (add-to-list 'gmpasm-filladapt-token-conversion-table
315                      '(gmpasm-comment . exact))
316         )
317       
318       (set (make-local-variable 'filladapt-token-table)
319            gmpasm-filladapt-token-table)
320       (set (make-local-variable 'filladapt-token-match-table)
321            gmpasm-filladapt-token-match-table)
322       (set (make-local-variable 'filladapt-token-conversion-table)
323            gmpasm-filladapt-token-conversion-table)
324     
325       ;; Add dnl and comment-start as fill prefixes.
326       ;; Comments in filladapt.el say filladapt-token-table must begin
327       ;; with ("^" beginning-of-line), so put our addition second.
328       (gmpasm-add-to-list-second 'filladapt-token-table
329                                  (list (concat "dnl[ \t]\\|" comment-regexp)
330                                        'gmpasm-comment))
331       ))
332   
333   (run-hooks 'gmpasm-mode-hook))
334
335
336 (defun gmpasm-comment-region-dnl (beg end &optional arg)
337   "(gmpasm-comment-region BEG END &option ARG)
338
339 Comment or uncomment each line in the region using `dnl'.
340 With \\[universal-argument] prefix arg, uncomment each line in region.
341 This is `comment-region', but using \"dnl\"."
342
343   (interactive "r\nP")
344   (let ((comment-start "dnl")
345         (comment-end ""))
346     (comment-region beg end arg)))
347
348
349 (provide 'gmpasm-mode)
350
351 ;;; gmpasm-mode.el ends here