asm-mode.el 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. ;;; asm-mode.el --- mode for editing assembler code
  2. ;; Copyright (C) 1991, 2001-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
  4. ;; Maintainer: FSF
  5. ;; Keywords: tools, languages
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; This mode was written by Eric S. Raymond <esr@snark.thyrsus.com>,
  19. ;; inspired by an earlier asm-mode by Martin Neitzel.
  20. ;; This minor mode is based on text mode. It defines a private abbrev table
  21. ;; that can be used to save abbrevs for assembler mnemonics. It binds just
  22. ;; five keys:
  23. ;;
  24. ;; TAB tab to next tab stop
  25. ;; : outdent preceding label, tab to tab stop
  26. ;; comment char place or move comment
  27. ;; asm-comment-char specifies which character this is;
  28. ;; you can use a different character in different
  29. ;; Asm mode buffers.
  30. ;; C-j, C-m newline and tab to tab stop
  31. ;;
  32. ;; Code is indented to the first tab stop level.
  33. ;; This mode runs two hooks:
  34. ;; 1) An asm-mode-set-comment-hook before the part of the initialization
  35. ;; depending on asm-comment-char, and
  36. ;; 2) an asm-mode-hook at the end of initialization.
  37. ;;; Code:
  38. (defgroup asm nil
  39. "Mode for editing assembler code."
  40. :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
  41. :group 'languages)
  42. (defcustom asm-comment-char ?\;
  43. "*The comment-start character assumed by Asm mode."
  44. :type 'character
  45. :group 'asm)
  46. (defvar asm-mode-syntax-table
  47. (let ((st (make-syntax-table)))
  48. (modify-syntax-entry ?\n "> b" st)
  49. (modify-syntax-entry ?/ ". 124b" st)
  50. (modify-syntax-entry ?* ". 23" st)
  51. st)
  52. "Syntax table used while in Asm mode.")
  53. (defvar asm-mode-abbrev-table nil
  54. "Abbrev table used while in Asm mode.")
  55. (define-abbrev-table 'asm-mode-abbrev-table ())
  56. (defvar asm-mode-map
  57. (let ((map (make-sparse-keymap)))
  58. ;; Note that the comment character isn't set up until asm-mode is called.
  59. (define-key map ":" 'asm-colon)
  60. (define-key map "\C-c;" 'comment-region)
  61. (define-key map "\C-j" 'newline-and-indent)
  62. (define-key map "\C-m" 'newline-and-indent)
  63. (define-key map [menu-bar asm-mode] (cons "Asm" (make-sparse-keymap)))
  64. (define-key map [menu-bar asm-mode comment-region]
  65. '(menu-item "Comment Region" comment-region
  66. :help "Comment or uncomment each line in the region"))
  67. (define-key map [menu-bar asm-mode newline-and-indent]
  68. '(menu-item "Insert Newline and Indent" newline-and-indent
  69. :help "Insert a newline, then indent according to major mode"))
  70. (define-key map [menu-bar asm-mode asm-colon]
  71. '(menu-item "Insert Colon" asm-colon
  72. :help "Insert a colon; if it follows a label, delete the label's indentation"))
  73. map)
  74. "Keymap for Asm mode.")
  75. (defconst asm-font-lock-keywords
  76. (append
  77. '(("^\\(\\(\\sw\\|\\s_\\)+\\)\\>:?[ \t]*\\(\\sw+\\(\\.\\sw+\\)*\\)?"
  78. (1 font-lock-function-name-face) (3 font-lock-keyword-face nil t))
  79. ;; label started from ".".
  80. ("^\\(\\.\\(\\sw\\|\\s_\\)+\\)\\>:"
  81. 1 font-lock-function-name-face)
  82. ("^\\((\\sw+)\\)?\\s +\\(\\(\\.?\\sw\\|\\s_\\)+\\(\\.\\sw+\\)*\\)"
  83. 2 font-lock-keyword-face)
  84. ;; directive started from ".".
  85. ("^\\(\\.\\(\\sw\\|\\s_\\)+\\)\\>[^:]?"
  86. 1 font-lock-keyword-face)
  87. ;; %register
  88. ("%\\sw+" . font-lock-variable-name-face))
  89. cpp-font-lock-keywords)
  90. "Additional expressions to highlight in Assembler mode.")
  91. ;;;###autoload
  92. (define-derived-mode asm-mode prog-mode "Assembler"
  93. "Major mode for editing typical assembler code.
  94. Features a private abbrev table and the following bindings:
  95. \\[asm-colon]\toutdent a preceding label, tab to next tab stop.
  96. \\[tab-to-tab-stop]\ttab to next tab stop.
  97. \\[asm-newline]\tnewline, then tab to next tab stop.
  98. \\[asm-comment]\tsmart placement of assembler comments.
  99. The character used for making comments is set by the variable
  100. `asm-comment-char' (which defaults to `?\\;').
  101. Alternatively, you may set this variable in `asm-mode-set-comment-hook',
  102. which is called near the beginning of mode initialization.
  103. Turning on Asm mode runs the hook `asm-mode-hook' at the end of initialization.
  104. Special commands:
  105. \\{asm-mode-map}"
  106. (setq local-abbrev-table asm-mode-abbrev-table)
  107. (set (make-local-variable 'font-lock-defaults) '(asm-font-lock-keywords))
  108. (set (make-local-variable 'indent-line-function) 'asm-indent-line)
  109. ;; Stay closer to the old TAB behavior (was tab-to-tab-stop).
  110. (set (make-local-variable 'tab-always-indent) nil)
  111. (run-hooks 'asm-mode-set-comment-hook)
  112. ;; Make our own local child of asm-mode-map
  113. ;; so we can define our own comment character.
  114. (use-local-map (nconc (make-sparse-keymap) asm-mode-map))
  115. (local-set-key (vector asm-comment-char) 'asm-comment)
  116. (set-syntax-table (make-syntax-table asm-mode-syntax-table))
  117. (modify-syntax-entry asm-comment-char "< b")
  118. (set (make-local-variable 'comment-start) (string asm-comment-char))
  119. (set (make-local-variable 'comment-add) 1)
  120. (set (make-local-variable 'comment-start-skip)
  121. "\\(?:\\s<+\\|/[/*]+\\)[ \t]*")
  122. (set (make-local-variable 'comment-end-skip) "[ \t]*\\(\\s>\\|\\*+/\\)")
  123. (set (make-local-variable 'comment-end) "")
  124. (setq fill-prefix "\t"))
  125. (defun asm-indent-line ()
  126. "Auto-indent the current line."
  127. (interactive)
  128. (let* ((savep (point))
  129. (indent (condition-case nil
  130. (save-excursion
  131. (forward-line 0)
  132. (skip-chars-forward " \t")
  133. (if (>= (point) savep) (setq savep nil))
  134. (max (asm-calculate-indentation) 0))
  135. (error 0))))
  136. (if savep
  137. (save-excursion (indent-line-to indent))
  138. (indent-line-to indent))))
  139. (defun asm-calculate-indentation ()
  140. (or
  141. ;; Flush labels to the left margin.
  142. (and (looking-at "\\(\\sw\\|\\s_\\)+:") 0)
  143. ;; Same thing for `;;;' comments.
  144. (and (looking-at "\\s<\\s<\\s<") 0)
  145. ;; Simple `;' comments go to the comment-column.
  146. (and (looking-at "\\s<\\(\\S<\\|\\'\\)") comment-column)
  147. ;; The rest goes at the first tab stop.
  148. (or (car tab-stop-list) tab-width)))
  149. (defun asm-colon ()
  150. "Insert a colon; if it follows a label, delete the label's indentation."
  151. (interactive)
  152. (let ((labelp nil))
  153. (save-excursion
  154. (skip-syntax-backward "w_")
  155. (skip-syntax-backward " ")
  156. (if (setq labelp (bolp)) (delete-horizontal-space)))
  157. (call-interactively 'self-insert-command)
  158. (when labelp
  159. (delete-horizontal-space)
  160. (tab-to-tab-stop))))
  161. ;; Obsolete since Emacs-22.1.
  162. (defalias 'asm-newline 'newline-and-indent)
  163. (defun asm-comment ()
  164. "Convert an empty comment to a `larger' kind, or start a new one.
  165. These are the known comment classes:
  166. 1 -- comment to the right of the code (at the comment-column)
  167. 2 -- comment on its own line, indented like code
  168. 3 -- comment on its own line, beginning at the left-most column.
  169. Suggested usage: while writing your code, trigger asm-comment
  170. repeatedly until you are satisfied with the kind of comment."
  171. (interactive)
  172. (comment-normalize-vars)
  173. (let (comempty comment)
  174. (save-excursion
  175. (beginning-of-line)
  176. (with-no-warnings
  177. (setq comment (comment-search-forward (line-end-position) t)))
  178. (setq comempty (looking-at "[ \t]*$")))
  179. (cond
  180. ;; Blank line? Then start comment at code indent level.
  181. ;; Just like `comment-dwim'. -stef
  182. ((save-excursion (beginning-of-line) (looking-at "^[ \t]*$"))
  183. (indent-according-to-mode)
  184. (insert asm-comment-char asm-comment-char ?\ ))
  185. ;; Nonblank line w/o comment => start a comment at comment-column.
  186. ;; Also: point before the comment => jump inside.
  187. ((or (null comment) (< (point) comment))
  188. (indent-for-comment))
  189. ;; Flush-left or non-empty comment present => just insert character.
  190. ((or (not comempty) (save-excursion (goto-char comment) (bolp)))
  191. (insert asm-comment-char))
  192. ;; Empty code-level comment => upgrade to next comment level.
  193. ((save-excursion (goto-char comment) (skip-chars-backward " \t") (bolp))
  194. (goto-char comment)
  195. (insert asm-comment-char)
  196. (indent-for-comment))
  197. ;; Empty comment ends non-empty code line => new comment above.
  198. (t
  199. (goto-char comment)
  200. (skip-chars-backward " \t")
  201. (delete-region (point) (line-end-position))
  202. (beginning-of-line) (insert "\n") (backward-char)
  203. (asm-comment)))))
  204. (provide 'asm-mode)
  205. ;;; asm-mode.el ends here