1 |
;;; asm-mode.el --- mode for editing assembler code |
;;; asm-mode.el --- mode for editing assembler code |
2 |
|
|
3 |
;; Copyright (C) 1991 Free Software Foundation, Inc. |
;; Copyright (C) 1991, 2003 Free Software Foundation, Inc. |
4 |
|
|
5 |
;; Author: Eric S. Raymond <esr@snark.thyrsus.com> |
;; Author: Eric S. Raymond <esr@snark.thyrsus.com> |
6 |
;; Maintainer: FSF |
;; Maintainer: FSF |
58 |
:type 'character |
:type 'character |
59 |
:group 'asm) |
:group 'asm) |
60 |
|
|
61 |
(defvar asm-mode-syntax-table nil |
(defvar asm-mode-syntax-table |
62 |
|
(let ((st (make-syntax-table))) |
63 |
|
(modify-syntax-entry ?\n ">" st) |
64 |
|
(modify-syntax-entry ?/ ". 14b" st) |
65 |
|
(modify-syntax-entry ?* ". 23b" st) |
66 |
|
st) |
67 |
"Syntax table used while in Asm mode.") |
"Syntax table used while in Asm mode.") |
68 |
|
|
69 |
(defvar asm-mode-abbrev-table nil |
(defvar asm-mode-abbrev-table nil |
70 |
"Abbrev table used while in Asm mode.") |
"Abbrev table used while in Asm mode.") |
71 |
(define-abbrev-table 'asm-mode-abbrev-table ()) |
(define-abbrev-table 'asm-mode-abbrev-table ()) |
72 |
|
|
73 |
(defvar asm-mode-map nil |
(defvar asm-mode-map |
74 |
|
(let ((map (make-sparse-keymap))) |
75 |
|
;; Note that the comment character isn't set up until asm-mode is called. |
76 |
|
(define-key map ":" 'asm-colon) |
77 |
|
(define-key map "\C-c;" 'comment-region) |
78 |
|
(define-key map "\C-j" 'newline-and-indent) |
79 |
|
(define-key map "\C-m" 'newline-and-indent) |
80 |
|
map) |
81 |
"Keymap for Asm mode.") |
"Keymap for Asm mode.") |
82 |
|
|
|
(if asm-mode-map |
|
|
nil |
|
|
(setq asm-mode-map (make-sparse-keymap)) |
|
|
;; Note that the comment character isn't set up until asm-mode is called. |
|
|
(define-key asm-mode-map ":" 'asm-colon) |
|
|
(define-key asm-mode-map "\C-c;" 'comment-region) |
|
|
(define-key asm-mode-map "\C-i" 'tab-to-tab-stop) |
|
|
(define-key asm-mode-map "\C-j" 'asm-newline) |
|
|
(define-key asm-mode-map "\C-m" 'asm-newline) |
|
|
) |
|
|
|
|
83 |
(defconst asm-font-lock-keywords |
(defconst asm-font-lock-keywords |
84 |
'(("^\\(\\(\\sw\\|\\s_\\)+\\)\\>:?[ \t]*\\(\\sw+\\(\\.[lLwWbBsS]\\)?\\)?" |
'(("^\\(\\(\\sw\\|\\s_\\)+\\)\\>:?[ \t]*\\(\\sw+\\(\\.\\sw+\\)*\\)?" |
85 |
(1 font-lock-function-name-face) (3 font-lock-keyword-face nil t)) |
(1 font-lock-function-name-face) (3 font-lock-keyword-face nil t)) |
86 |
("^\\s +\\(\\(\\sw\\|\\s_\\)+\\(\\.[lLwWbBsS]\\)?\\)" 1 font-lock-keyword-face)) |
("^\\((\\sw+)\\)?\\s +\\(\\(\\sw\\|\\s_\\)+\\(\\.\\sw+\\)*\\)" |
87 |
|
2 font-lock-keyword-face)) |
88 |
"Additional expressions to highlight in Assembler mode.") |
"Additional expressions to highlight in Assembler mode.") |
89 |
|
|
|
(defvar asm-code-level-empty-comment-pattern nil) |
|
|
(defvar asm-flush-left-empty-comment-pattern nil) |
|
|
(defvar asm-inline-empty-comment-pattern nil) |
|
|
|
|
90 |
;;;###autoload |
;;;###autoload |
91 |
(defun asm-mode () |
(defun asm-mode () |
92 |
"Major mode for editing typical assembler code. |
"Major mode for editing typical assembler code. |
106 |
Turning on Asm mode runs the hook `asm-mode-hook' at the end of initialization. |
Turning on Asm mode runs the hook `asm-mode-hook' at the end of initialization. |
107 |
|
|
108 |
Special commands: |
Special commands: |
109 |
\\{asm-mode-map} |
\\{asm-mode-map}" |
|
" |
|
110 |
(interactive) |
(interactive) |
111 |
(kill-all-local-variables) |
(kill-all-local-variables) |
112 |
(setq mode-name "Assembler") |
(setq mode-name "Assembler") |
114 |
(setq local-abbrev-table asm-mode-abbrev-table) |
(setq local-abbrev-table asm-mode-abbrev-table) |
115 |
(make-local-variable 'font-lock-defaults) |
(make-local-variable 'font-lock-defaults) |
116 |
(setq font-lock-defaults '(asm-font-lock-keywords)) |
(setq font-lock-defaults '(asm-font-lock-keywords)) |
117 |
(make-local-variable 'asm-mode-syntax-table) |
(set (make-local-variable 'indent-line-function) 'asm-indent-line) |
118 |
(setq asm-mode-syntax-table (make-syntax-table)) |
;; Stay closer to the old TAB behavior (was tab-to-tab-stop). |
119 |
(set-syntax-table asm-mode-syntax-table) |
(set (make-local-variable 'tab-always-indent) nil) |
120 |
|
|
121 |
(run-hooks 'asm-mode-set-comment-hook) |
(run-hooks 'asm-mode-set-comment-hook) |
122 |
;; Make our own local child of asm-mode-map |
;; Make our own local child of asm-mode-map |
123 |
;; so we can define our own comment character. |
;; so we can define our own comment character. |
124 |
(use-local-map (nconc (make-sparse-keymap) asm-mode-map)) |
(use-local-map (nconc (make-sparse-keymap) asm-mode-map)) |
125 |
(local-set-key (vector asm-comment-char) 'asm-comment) |
(local-set-key (vector asm-comment-char) 'asm-comment) |
126 |
|
(set-syntax-table (make-syntax-table asm-mode-syntax-table)) |
127 |
|
(modify-syntax-entry asm-comment-char "<") |
128 |
|
|
129 |
(modify-syntax-entry asm-comment-char |
(make-local-variable 'comment-start) |
130 |
"<" asm-mode-syntax-table) |
(setq comment-start (string asm-comment-char)) |
131 |
(modify-syntax-entry ?\n |
(make-local-variable 'comment-add) |
132 |
">" asm-mode-syntax-table) |
(setq comment-add 1) |
133 |
(let ((cs (regexp-quote (char-to-string asm-comment-char)))) |
(make-local-variable 'comment-start-skip) |
134 |
(make-local-variable 'comment-start) |
(setq comment-start-skip "\\(?:\\s<+\\|/\\*+\\)[ \t]*") |
135 |
(setq comment-start (concat (char-to-string asm-comment-char) " ")) |
(make-local-variable 'comment-end-skip) |
136 |
(make-local-variable 'comment-start-skip) |
(setq comment-end-skip "[ \t]*\\(\\s>\\|\\*+/\\)") |
|
(setq comment-start-skip (concat cs "+[ \t]*")) |
|
|
(setq asm-inline-empty-comment-pattern (concat "^.+" cs "+ *$")) |
|
|
(setq asm-code-level-empty-comment-pattern (concat "^[\t ]+" cs cs " *$")) |
|
|
(setq asm-flush-left-empty-comment-pattern (concat "^" cs cs cs " *$")) |
|
|
) |
|
137 |
(make-local-variable 'comment-end) |
(make-local-variable 'comment-end) |
138 |
(setq comment-end "") |
(setq comment-end "") |
139 |
(setq fill-prefix "\t") |
(setq fill-prefix "\t") |
140 |
(run-hooks 'asm-mode-hook)) |
(run-mode-hooks 'asm-mode-hook)) |
141 |
|
|
142 |
(defun asm-colon () |
(defun asm-indent-line () |
143 |
"Insert a colon; if it follows a label, delete the label's indentation." |
"Auto-indent the current line." |
144 |
(interactive) |
(interactive) |
145 |
(save-excursion |
(let* ((savep (point)) |
146 |
(beginning-of-line) |
(indent (condition-case nil |
147 |
(if (looking-at "[ \t]+\\(\\sw\\|\\s_\\)+$") |
(save-excursion |
148 |
(delete-horizontal-space))) |
(forward-line 0) |
149 |
(insert ":") |
(skip-chars-forward " \t") |
150 |
(tab-to-tab-stop) |
(if (>= (point) savep) (setq savep nil)) |
151 |
) |
(max (asm-calculate-indentation) 0)) |
152 |
|
(error 0)))) |
153 |
|
(if savep |
154 |
|
(save-excursion (indent-line-to indent)) |
155 |
|
(indent-line-to indent)))) |
156 |
|
|
157 |
|
(defun asm-calculate-indentation () |
158 |
|
(or |
159 |
|
;; Flush labels to the left margin. |
160 |
|
(and (looking-at "\\(\\sw\\|\\s_\\)+:") 0) |
161 |
|
;; Same thing for `;;;' comments. |
162 |
|
(and (looking-at "\\s<\\s<\\s<") 0) |
163 |
|
;; Simple `;' comments go to the comment-column. |
164 |
|
(and (looking-at "\\s<\\(\\S<\\|\\'\\)") comment-column) |
165 |
|
;; The rest goes at the first tab stop. |
166 |
|
(or (car tab-stop-list) tab-width))) |
167 |
|
|
168 |
(defun asm-newline () |
(defun asm-colon () |
169 |
"Insert LFD + fill-prefix, to bring us back to code-indent level." |
"Insert a colon; if it follows a label, delete the label's indentation." |
170 |
(interactive) |
(interactive) |
171 |
(if (eolp) (delete-horizontal-space)) |
(let ((labelp nil)) |
172 |
(insert "\n") |
(save-excursion |
173 |
(tab-to-tab-stop) |
(skip-syntax-backward "w_") |
174 |
) |
(skip-syntax-backward " ") |
175 |
|
(if (setq labelp (bolp)) (delete-horizontal-space))) |
176 |
(defun asm-line-matches (pattern &optional withcomment) |
(call-interactively 'self-insert-command) |
177 |
(save-excursion |
(when labelp |
178 |
(beginning-of-line) |
(delete-horizontal-space) |
179 |
(looking-at pattern))) |
(tab-to-tab-stop)))) |
|
|
|
|
(defun asm-pop-comment-level () |
|
|
;; Delete an empty comment ending current line. Then set up for a new one, |
|
|
;; on the current line if it was all comment, otherwise above it |
|
|
(end-of-line) |
|
|
(delete-horizontal-space) |
|
|
(while (= (preceding-char) asm-comment-char) |
|
|
(delete-backward-char 1)) |
|
|
(delete-horizontal-space) |
|
|
(if (bolp) |
|
|
nil |
|
|
(beginning-of-line) |
|
|
(open-line 1)) |
|
|
) |
|
180 |
|
|
181 |
|
;; Obsolete since Emacs-21.4. |
182 |
|
(defalias 'asm-newline 'newline-and-indent) |
183 |
|
|
184 |
(defun asm-comment () |
(defun asm-comment () |
185 |
"Convert an empty comment to a `larger' kind, or start a new one. |
"Convert an empty comment to a `larger' kind, or start a new one. |
192 |
Suggested usage: while writing your code, trigger asm-comment |
Suggested usage: while writing your code, trigger asm-comment |
193 |
repeatedly until you are satisfied with the kind of comment." |
repeatedly until you are satisfied with the kind of comment." |
194 |
(interactive) |
(interactive) |
195 |
|
(comment-normalize-vars) |
196 |
|
(let (comempty comment) |
197 |
|
(save-excursion |
198 |
|
(beginning-of-line) |
199 |
|
(setq comment (comment-search-forward (line-end-position) t)) |
200 |
|
(setq comempty (looking-at "[ \t]*$"))) |
201 |
|
|
202 |
(cond |
(cond |
203 |
|
|
204 |
;; Blank line? Then start comment at code indent level. |
;; Blank line? Then start comment at code indent level. |
205 |
((asm-line-matches "^[ \t]*$") |
;; Just like `comment-dwim'. -stef |
206 |
(delete-horizontal-space) |
((save-excursion (beginning-of-line) (looking-at "^[ \t]*$")) |
207 |
(tab-to-tab-stop) |
(indent-according-to-mode) |
208 |
(insert asm-comment-char comment-start)) |
(insert asm-comment-char asm-comment-char ?\ )) |
209 |
|
|
210 |
;; Nonblank line with no comment chars in it? |
;; Nonblank line w/o comment => start a comment at comment-column. |
211 |
;; Then start a comment at the current comment column |
;; Also: point before the comment => jump inside. |
212 |
((asm-line-matches (format "^[^%c\n]+$" asm-comment-char)) |
((or (null comment) (< (point) comment)) |
213 |
(indent-for-comment)) |
(indent-for-comment)) |
214 |
|
|
215 |
;; Flush-left comment present? Just insert character. |
;; Flush-left or non-empty comment present => just insert character. |
216 |
((asm-line-matches asm-flush-left-empty-comment-pattern) |
((or (not comempty) (save-excursion (goto-char comment) (bolp))) |
217 |
(insert asm-comment-char)) |
(insert asm-comment-char)) |
218 |
|
|
219 |
;; Empty code-level comment already present? |
;; Empty code-level comment => upgrade to next comment level. |
220 |
;; Then start flush-left comment, on line above if this one is nonempty. |
((save-excursion (goto-char comment) (skip-chars-backward " \t") (bolp)) |
221 |
((asm-line-matches asm-code-level-empty-comment-pattern) |
(goto-char comment) |
222 |
(asm-pop-comment-level) |
(insert asm-comment-char) |
223 |
(insert asm-comment-char asm-comment-char comment-start)) |
(indent-for-comment)) |
|
|
|
|
;; Empty comment ends line? |
|
|
;; Then make code-level comment, on line above if this one is nonempty. |
|
|
((asm-line-matches asm-inline-empty-comment-pattern) |
|
|
(asm-pop-comment-level) |
|
|
(tab-to-tab-stop) |
|
|
(insert asm-comment-char comment-start)) |
|
224 |
|
|
225 |
;; If all else fails, insert character |
;; Empty comment ends non-empty code line => new comment above. |
226 |
(t |
(t |
227 |
(insert asm-comment-char)) |
(goto-char comment) |
228 |
|
(skip-chars-backward " \t") |
229 |
) |
(delete-region (point) (line-end-position)) |
230 |
(end-of-line)) |
(beginning-of-line) (insert "\n") (backward-char) |
231 |
|
(asm-comment))))) |
232 |
|
|
233 |
(provide 'asm-mode) |
(provide 'asm-mode) |
234 |
|
|