Blame mpn/lisp/gmpasm-mode.el

Packit 5c3484
;;; gmpasm-mode.el -- GNU MP asm and m4 editing mode.
Packit 5c3484
Packit 5c3484
Packit 5c3484
;; Copyright 1999-2002 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
;;   This file is part of the GNU MP Library.
Packit 5c3484
;;   
Packit 5c3484
;;   The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
;;   it under the terms of either:
Packit 5c3484
;;   
Packit 5c3484
;;     * the GNU Lesser General Public License as published by the Free
Packit 5c3484
;;       Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
;;       option) any later version.
Packit 5c3484
;;   
Packit 5c3484
;;   or
Packit 5c3484
;;   
Packit 5c3484
;;     * the GNU General Public License as published by the Free Software
Packit 5c3484
;;       Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
;;       later version.
Packit 5c3484
;;   
Packit 5c3484
;;   or both in parallel, as here.
Packit 5c3484
;;   
Packit 5c3484
;;   The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
;;   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
;;   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
;;   for more details.
Packit 5c3484
;;   
Packit 5c3484
;;   You should have received copies of the GNU General Public License and the
Packit 5c3484
;;   GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
;;   see https://www.gnu.org/licenses/.
Packit 5c3484
Packit 5c3484
Packit 5c3484
;;; Commentary:
Packit 5c3484
;;
Packit 5c3484
;; gmpasm-mode is a major mode for editing m4 processed assembler code and
Packit 5c3484
;; m4 macro files in GMP.  It's similar to m4-mode, but has a number of
Packit 5c3484
;; settings better suited to GMP.
Packit 5c3484
;;
Packit 5c3484
;;
Packit 5c3484
;; Install
Packit 5c3484
;; -------
Packit 5c3484
;;
Packit 5c3484
;; To make M-x gmpasm-mode available, put gmpasm-mode.el somewhere in your
Packit 5c3484
;; load-path and the following in your .emacs
Packit 5c3484
;;
Packit 5c3484
;;	(autoload 'gmpasm-mode "gmpasm-mode" nil t)
Packit 5c3484
;;
Packit 5c3484
;; To use gmpasm-mode automatically on all .asm and .m4 files, put the
Packit 5c3484
;; following in your .emacs
Packit 5c3484
;;
Packit 5c3484
;;	(add-to-list 'auto-mode-alist '("\\.asm\\'" . gmpasm-mode))
Packit 5c3484
;;	(add-to-list 'auto-mode-alist '("\\.m4\\'" . gmpasm-mode))
Packit 5c3484
;;
Packit 5c3484
;; To have gmpasm-mode only on gmp files, try instead something like the
Packit 5c3484
;; following, which uses it only in a directory starting with "gmp", or a
Packit 5c3484
;; sub-directory of such.
Packit 5c3484
;;
Packit 5c3484
;;	(add-to-list 'auto-mode-alist
Packit 5c3484
;;	             '("/gmp.*/.*\\.\\(asm\\|m4\\)\\'" . gmpasm-mode))
Packit 5c3484
;;
Packit 5c3484
;; Byte compiling will slightly speed up loading.  If you want a docstring
Packit 5c3484
;; in the autoload you can use M-x update-file-autoloads if you set it up
Packit 5c3484
;; right.
Packit 5c3484
;;
Packit 5c3484
;;
Packit 5c3484
;; Emacsen
Packit 5c3484
;; -------
Packit 5c3484
;;
Packit 5c3484
;; GNU Emacs 20.x, 21.x and XEmacs 20.x all work well.  GNU Emacs 19.x
Packit 5c3484
;; should work if replacements for the various 20.x-isms are available,
Packit 5c3484
;; though comment-region with "C" doesn't do the right thing.
Packit 5c3484
Packit 5c3484
Packit 5c3484
;;; Code:
Packit 5c3484
Packit 5c3484
(defgroup gmpasm nil
Packit 5c3484
  "GNU MP m4 and asm editing."
Packit 5c3484
  :prefix "gmpasm-"
Packit 5c3484
  :group 'languages)
Packit 5c3484
Packit 5c3484
(defcustom gmpasm-mode-hook nil
Packit 5c3484
  "*Hook called by `gmpasm-mode'."
Packit 5c3484
  :type 'hook
Packit 5c3484
  :group 'gmpasm)
Packit 5c3484
Packit 5c3484
(defcustom gmpasm-comment-start-regexp "\\([#;!@*|C]\\|//\\)"
Packit 5c3484
  "*Regexp matching possible comment styles.
Packit 5c3484
See `gmpasm-mode' docstring for how this is used.
Packit 5c3484
Packit 5c3484
Commenting styles within GMP include
Packit 5c3484
  #   - alpha, i386, i960, vax, traditional unix
Packit 5c3484
  ;   - a29k, clipper, hppa, m88k, ppc
Packit 5c3484
  !   - sh, sparc, z8000
Packit 5c3484
  |   - m68k
Packit 5c3484
  @   - arm
Packit 5c3484
  *   - cray
Packit 5c3484
  C   - GMP m4, see mpn/asm-defs.m4
Packit 5c3484
  //  - ia64"
Packit 5c3484
  :type 'regexp
Packit 5c3484
  :group 'gmpasm)
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defun gmpasm-add-to-list-second (list-var element)
Packit 5c3484
  "(gmpasm-add-to-list-second LIST-VAR ELEMENT)
Packit 5c3484
Packit 5c3484
Add ELEMENT to LIST-VAR as the second element in the list, if it isn't
Packit 5c3484
already in the list.  If LIST-VAR is nil, then ELEMENT is just added as the
Packit 5c3484
sole element in the list.
Packit 5c3484
Packit 5c3484
This is like `add-to-list', but it puts the new value second in the list.
Packit 5c3484
Packit 5c3484
The first cons cell is copied rather than changed in-place, so references to
Packit 5c3484
the list elsewhere won't be affected."
Packit 5c3484
Packit 5c3484
  (if (member element (symbol-value list-var))
Packit 5c3484
      (symbol-value list-var)
Packit 5c3484
    (set list-var
Packit 5c3484
	 (if (symbol-value list-var)
Packit 5c3484
	     (cons (car (symbol-value list-var))
Packit 5c3484
		   (cons element
Packit 5c3484
			 (cdr (symbol-value list-var))))
Packit 5c3484
	   (list element)))))
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defun gmpasm-remove-from-list (list-var element)
Packit 5c3484
  "(gmpasm-remove-from-list LIST-VAR ELEMENT)
Packit 5c3484
Packit 5c3484
Remove ELEMENT from LIST-VAR, using `copy-sequence' and `delete'.
Packit 5c3484
This is vaguely like `add-to-list', but the element is removed from the list.
Packit 5c3484
The list is copied rather than changed in-place, so references to it elsewhere
Packit 5c3484
aren't affected."
Packit 5c3484
Packit 5c3484
;; Only the portion of the list up to the removed element needs to be
Packit 5c3484
;; copied, but there's no need to bother arranging that, since this function
Packit 5c3484
;; is only used for a couple of initializations.
Packit 5c3484
Packit 5c3484
  (set list-var (delete element (copy-sequence (symbol-value list-var)))))
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defvar gmpasm-mode-map
Packit 5c3484
  (let ((map (make-sparse-keymap)))
Packit 5c3484
Packit 5c3484
    ;; assembler and dnl commenting
Packit 5c3484
    (define-key map "\C-c\C-c" 'comment-region)
Packit 5c3484
    (define-key map "\C-c\C-d" 'gmpasm-comment-region-dnl)
Packit 5c3484
Packit 5c3484
    ;; kill an M-x compile, since it's not hard to put m4 into an infinite
Packit 5c3484
    ;; loop
Packit 5c3484
    (define-key map "\C-c\C-k" 'kill-compilation)
Packit 5c3484
Packit 5c3484
    map)
Packit 5c3484
  "Keymap for `gmpasm-mode'.")
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defvar gmpasm-mode-syntax-table
Packit 5c3484
  (let ((table (make-syntax-table)))
Packit 5c3484
    ;; underscore left as a symbol char, like C mode
Packit 5c3484
Packit 5c3484
    ;; m4 quotes
Packit 5c3484
    (modify-syntax-entry ?`  "('"  table)
Packit 5c3484
    (modify-syntax-entry ?'  ")`"  table)
Packit 5c3484
Packit 5c3484
    table)
Packit 5c3484
  "Syntax table used in `gmpasm-mode'.
Packit 5c3484
Packit 5c3484
'#' and '\n' aren't set as comment syntax.  In m4 these are a comment
Packit 5c3484
outside quotes, but not inside.  Omitting a syntax entry ensures that when
Packit 5c3484
inside quotes emacs treats parentheses and apostrophes the same way that m4
Packit 5c3484
does.  When outside quotes this is not quite right, but having it right when
Packit 5c3484
nesting expressions is more important.
Packit 5c3484
Packit 5c3484
'*', '!' or '|' aren't setup as comment syntax either, on CPUs which use
Packit 5c3484
these for comments.  The GMP macro setups don't set them in m4 changecom(),
Packit 5c3484
since that prevents them being used in eval() expressions, and on that basis
Packit 5c3484
they don't change the way quotes and parentheses are treated by m4 and
Packit 5c3484
should be treated by emacs.")
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defvar gmpasm-font-lock-keywords
Packit 5c3484
  (eval-when-compile
Packit 5c3484
    (list
Packit 5c3484
     (cons
Packit 5c3484
      (concat
Packit 5c3484
       "\\b"
Packit 5c3484
       (regexp-opt
Packit 5c3484
	'("deflit" "defreg" "defframe" "defframe_pushl"
Packit 5c3484
	  "define_not_for_expansion"
Packit 5c3484
	  "m4_error" "m4_warning"
Packit 5c3484
	  "ASM_START" "ASM_END"
Packit 5c3484
	  "PROLOGUE" "PROLOGUE_GP" "MULFUNC_PROLOGUE" "EPILOGUE"
Packit 5c3484
	  "DATASTART" "DATAEND"
Packit 5c3484
	  "forloop"
Packit 5c3484
	  "TEXT" "DATA" "ALIGN" "W32" "FLOAT64"
Packit 5c3484
	  "builtin" "changecom" "changequote" "changeword" "debugfile"
Packit 5c3484
	  "debugmode" "decr" "define" "defn" "divert" "divnum" "dumpdef"
Packit 5c3484
	  "errprint" "esyscmd" "eval" "__file__" "format" "gnu" "ifdef"
Packit 5c3484
	  "ifelse" "include" "incr" "index" "indir" "len" "__line__"
Packit 5c3484
	  "m4exit" "m4wrap" "maketemp" "patsubst" "popdef" "pushdef"
Packit 5c3484
	  "regexp" "shift" "sinclude" "substr" "syscmd" "sysval"
Packit 5c3484
	  "traceoff" "traceon" "translit" "undefine" "undivert" "unix")
Packit 5c3484
	t)
Packit 5c3484
       "\\b") 'font-lock-keyword-face)))
Packit 5c3484
Packit 5c3484
  "`font-lock-keywords' for `gmpasm-mode'.
Packit 5c3484
Packit 5c3484
The keywords are m4 builtins and some of the GMP macros used in asm files.
Packit 5c3484
L doesn't look good fontified, so it's omitted.
Packit 5c3484
Packit 5c3484
The right assembler comment regexp is added dynamically buffer-local (with
Packit 5c3484
dnl too).")
Packit 5c3484
Packit 5c3484
Packit 5c3484
;; Initialized if gmpasm-mode finds filladapt loaded.
Packit 5c3484
(defvar gmpasm-filladapt-token-table nil
Packit 5c3484
  "Filladapt token table used in `gmpasm-mode'.")
Packit 5c3484
(defvar gmpasm-filladapt-token-match-table nil
Packit 5c3484
  "Filladapt token match table used in `gmpasm-mode'.")
Packit 5c3484
(defvar gmpasm-filladapt-token-conversion-table nil
Packit 5c3484
  "Filladapt token conversion table used in `gmpasm-mode'.")
Packit 5c3484
Packit 5c3484
Packit 5c3484
;;;###autoload
Packit 5c3484
(defun gmpasm-mode ()
Packit 5c3484
  "A major mode for editing GNU MP asm and m4 files.
Packit 5c3484
Packit 5c3484
\\{gmpasm-mode-map}
Packit 5c3484
`comment-start' and `comment-end' are set buffer-local to assembler
Packit 5c3484
commenting appropriate for the CPU by looking for something matching
Packit 5c3484
`gmpasm-comment-start-regexp' at the start of a line, or \"#\" is used if
Packit 5c3484
there's no match (if \"#\" isn't what you want, type in a desired comment
Packit 5c3484
and do \\[gmpasm-mode] to reinitialize).
Packit 5c3484
Packit 5c3484
`adaptive-fill-regexp' is set buffer-local to the standard regexp with
Packit 5c3484
`comment-start' and dnl added.  If filladapt.el has been loaded it similarly
Packit 5c3484
gets `comment-start' and dnl added as buffer-local fill prefixes.
Packit 5c3484
Packit 5c3484
Font locking has the m4 builtins, some of the GMP macros, m4 dnl commenting,
Packit 5c3484
and assembler commenting (based on the `comment-start' determined).
Packit 5c3484
Packit 5c3484
Note that `gmpasm-comment-start-regexp' is only matched as a whole word, so
Packit 5c3484
the `C' in it is only matched as a whole word, not on something that happens
Packit 5c3484
to start with `C'.  Also it's only the particular `comment-start' determined
Packit 5c3484
that's added for filling etc, not the whole `gmpasm-comment-start-regexp'.
Packit 5c3484
Packit 5c3484
`gmpasm-mode-hook' is run after initializations are complete."
Packit 5c3484
Packit 5c3484
  (interactive)
Packit 5c3484
  (kill-all-local-variables)
Packit 5c3484
  (setq major-mode 'gmpasm-mode
Packit 5c3484
        mode-name  "gmpasm")
Packit 5c3484
  (use-local-map gmpasm-mode-map)
Packit 5c3484
  (set-syntax-table gmpasm-mode-syntax-table)
Packit 5c3484
  (setq fill-column 76)
Packit 5c3484
Packit 5c3484
  ;; Short instructions might fit with 32, but anything with labels or
Packit 5c3484
  ;; expressions soon needs the comments pushed out to column 40.
Packit 5c3484
  (setq comment-column 40)
Packit 5c3484
Packit 5c3484
  ;; Don't want to find out the hard way which dumb assemblers don't like a
Packit 5c3484
  ;; missing final newline.
Packit 5c3484
  (set (make-local-variable 'require-final-newline) t)
Packit 5c3484
Packit 5c3484
  ;; The first match of gmpasm-comment-start-regexp at the start of a line
Packit 5c3484
  ;; determines comment-start, or "#" if no match.
Packit 5c3484
  (set (make-local-variable 'comment-start)
Packit 5c3484
       (save-excursion
Packit 5c3484
	 (goto-char (point-min))
Packit 5c3484
	 (if (re-search-forward
Packit 5c3484
	      (concat "^\\(" gmpasm-comment-start-regexp "\\)\\(\\s-\\|$\\)")
Packit 5c3484
	      nil t)
Packit 5c3484
	     (match-string 1)
Packit 5c3484
	   "#")))
Packit 5c3484
  (set (make-local-variable 'comment-end) "")
Packit 5c3484
Packit 5c3484
  ;; If comment-start ends in an alphanumeric then \b is used to match it
Packit 5c3484
  ;; only as a separate word.  The test is for an alphanumeric rather than
Packit 5c3484
  ;; \w since we might try # or ! as \w characters but without wanting \b on
Packit 5c3484
  ;; them.
Packit 5c3484
  (let ((comment-regexp
Packit 5c3484
	 (concat (regexp-quote comment-start)
Packit 5c3484
		 (if (string-match "[a-zA-Z0-9]\\'" comment-start) "\\b"))))
Packit 5c3484
Packit 5c3484
    ;; Whitespace is required before a comment-start so m4 $# doesn't match
Packit 5c3484
    ;; when comment-start is "#".
Packit 5c3484
    (set (make-local-variable 'comment-start-skip)
Packit 5c3484
	 (concat "\\(^\\|\\s-\\)\\(\\<dnl\\>\\|" comment-regexp "\\)[ \t]*"))
Packit 5c3484
Packit 5c3484
    ;; Comment fontification based on comment-start, and always with dnl.
Packit 5c3484
    ;; Same treatment of a space before "#" as in comment-start-skip, but
Packit 5c3484
    ;; don't fontify that space.
Packit 5c3484
    (add-to-list (make-local-variable 'gmpasm-font-lock-keywords)
Packit 5c3484
		 (list (concat "\\(^\\|\\s-\\)\\(\\(\\<dnl\\>\\|"
Packit 5c3484
			       comment-regexp
Packit 5c3484
			       "\\).*$\\)")
Packit 5c3484
		       2 'font-lock-comment-face))
Packit 5c3484
Packit 5c3484
    (set (make-local-variable 'font-lock-defaults)
Packit 5c3484
	 '(gmpasm-font-lock-keywords
Packit 5c3484
	   t	         ; no syntactic fontification (of strings etc)
Packit 5c3484
	   nil           ; no case-fold
Packit 5c3484
	   ((?_ . "w"))  ; _ part of a word while fontifying
Packit 5c3484
	   ))
Packit 5c3484
Packit 5c3484
    ;; Paragraphs are separated by blank lines, or lines with only dnl or
Packit 5c3484
    ;; comment-start.
Packit 5c3484
    (set (make-local-variable 'paragraph-separate)
Packit 5c3484
	 (concat "[ \t\f]*\\(\\(" comment-regexp "\\|dnl\\)[ \t]*\\)*$"))
Packit 5c3484
    (set (make-local-variable 'paragraph-start)
Packit 5c3484
	 (concat "\f\\|" paragraph-separate))
Packit 5c3484
Packit 5c3484
    ;; Some sort of "def...(" m4 define, possibly with ` for quoting.
Packit 5c3484
    ;; Could do something with PROLOGUE here, but in GMP the filename is
Packit 5c3484
    ;; enough, it's not normally necessary to say the function name.
Packit 5c3484
    (set (make-local-variable 'add-log-current-defun-header-regexp)
Packit 5c3484
	 "^def[a-z0-9_]+(`?\\([a-zA-Z0-9_]+\\)")
Packit 5c3484
Packit 5c3484
    ;; Adaptive fill gets dnl and comment-start as comment style prefixes on
Packit 5c3484
    ;; top of the standard regexp (which has # and ; already actually).
Packit 5c3484
    (set (make-local-variable 'adaptive-fill-regexp)
Packit 5c3484
	 (concat "[ \t]*\\(\\("
Packit 5c3484
		 comment-regexp
Packit 5c3484
		 "\\|dnl\\|[-|#;>*]+\\|(?[0-9]+[.)]\\)[ \t]*\\)*"))
Packit 5c3484
    (set (make-local-variable 'adaptive-fill-first-line-regexp)
Packit 5c3484
	 "\\`\\([ \t]*dnl\\)?[ \t]*\\'")
Packit 5c3484
Packit 5c3484
    (when (fboundp 'filladapt-mode)
Packit 5c3484
      (unless gmpasm-filladapt-token-table
Packit 5c3484
	(setq gmpasm-filladapt-token-table
Packit 5c3484
	      filladapt-token-table)
Packit 5c3484
	(setq gmpasm-filladapt-token-match-table
Packit 5c3484
	      filladapt-token-match-table)
Packit 5c3484
	(setq gmpasm-filladapt-token-conversion-table
Packit 5c3484
	      filladapt-token-conversion-table)
Packit 5c3484
Packit 5c3484
	;; Numbered bullet points like "2.1" get matched at the start of a
Packit 5c3484
	;; line when it's really something like "2.1 cycles/limb", so remove
Packit 5c3484
	;; this from the list.  The regexp for "1.", "2." etc is left
Packit 5c3484
	;; though.
Packit 5c3484
	(gmpasm-remove-from-list 'gmpasm-filladapt-token-table
Packit 5c3484
				 '("[0-9]+\\(\\.[0-9]+\\)+[ \t]"
Packit 5c3484
				   bullet))
Packit 5c3484
Packit 5c3484
	;; "%" as a comment prefix interferes with register names on some
Packit 5c3484
	;; CPUs, like %eax on x86, so remove this.
Packit 5c3484
	(gmpasm-remove-from-list 'gmpasm-filladapt-token-table
Packit 5c3484
				 '("%+" postscript-comment))
Packit 5c3484
Packit 5c3484
	(add-to-list 'gmpasm-filladapt-token-match-table
Packit 5c3484
		     '(gmpasm-comment gmpasm-comment))
Packit 5c3484
	(add-to-list 'gmpasm-filladapt-token-conversion-table
Packit 5c3484
		     '(gmpasm-comment . exact)))
Packit 5c3484
Packit 5c3484
      (set (make-local-variable 'filladapt-token-table)
Packit 5c3484
	   gmpasm-filladapt-token-table)
Packit 5c3484
      (set (make-local-variable 'filladapt-token-match-table)
Packit 5c3484
	   gmpasm-filladapt-token-match-table)
Packit 5c3484
      (set (make-local-variable 'filladapt-token-conversion-table)
Packit 5c3484
	   gmpasm-filladapt-token-conversion-table)
Packit 5c3484
Packit 5c3484
      ;; Add dnl and comment-start as fill prefixes.
Packit 5c3484
      ;; Comments in filladapt.el say filladapt-token-table must begin
Packit 5c3484
      ;; with ("^" beginning-of-line), so put our addition second.
Packit 5c3484
      (gmpasm-add-to-list-second 'filladapt-token-table
Packit 5c3484
				 (list (concat "dnl[ \t]\\|" comment-regexp)
Packit 5c3484
				       'gmpasm-comment))))
Packit 5c3484
Packit 5c3484
  (run-hooks 'gmpasm-mode-hook))
Packit 5c3484
Packit 5c3484
Packit 5c3484
(defun gmpasm-comment-region-dnl (beg end &optional arg)
Packit 5c3484
  "(gmpasm-comment-region-dnl BEG END &optional ARG)
Packit 5c3484
Packit 5c3484
Comment or uncomment each line in the region using `dnl'.
Packit 5c3484
With \\[universal-argument] prefix arg, uncomment each line in region.
Packit 5c3484
This is `comment-region', but using \"dnl\"."
Packit 5c3484
Packit 5c3484
  (interactive "r\nP")
Packit 5c3484
  (let ((comment-start "dnl")
Packit 5c3484
	(comment-end ""))
Packit 5c3484
    (comment-region beg end arg)))
Packit 5c3484
Packit 5c3484
Packit 5c3484
(provide 'gmpasm-mode)
Packit 5c3484
Packit 5c3484
;;; gmpasm-mode.el ends here