comparison lisp/progmodes/cmacexp.el @ 7008:fd080d04dfe2

(c-macro-expansion): changed the algorithm to allow __FILE__ and __LINE__ directives to be expanded correctly. (c-macro-expansion): use a forth optional argument DISPLAY meaning it should print messages at the start and end of preprocessing. All callers changed. (c-macro-expand): Don't display message here.
author Richard M. Stallman <rms@gnu.org>
date Thu, 21 Apr 1994 18:40:14 +0000
parents 9d977a1a7147
children 4fd40bd394fe
comparison
equal deleted inserted replaced
7007:52b0ebfd3191 7008:fd080d04dfe2
1 ;;; cmacexp.el --- expand C macros in a region 1 ;;; cmacexp.el --- expand C macros in a region
2 2
3 ;; Copyright (C) 1992 Free Software Foundation, Inc. 3 ;; Copyright (C) 1992 Free Software Foundation, Inc.
4 4
5 ;; Author: Francesco Potorti` <pot@cnuce.cnr.it> 5 ;; Author: Francesco Potorti` <pot@cnuce.cnr.it>
6 ;; Version: $Id: cmacexp.el,v 1.11 1994/04/20 06:12:03 rms Exp rms $ 6 ;; Version: $Id: cmacexp.el 1.14 1994/04/20 15:50:48 pot Exp $
7 ;; Adapted-By: ESR 7 ;; Adapted-By: ESR
8 ;; Keywords: c 8 ;; Keywords: c
9 9
10 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
11 11
23 ;; along with GNU Emacs; see the file COPYING. If not, write to 23 ;; along with GNU Emacs; see the file COPYING. If not, write to
24 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 24 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25 25
26 ;; USAGE ============================================================= 26 ;; USAGE =============================================================
27 27
28 ;; In C mode C-M-x is bound to c-macro-expand. The result of the 28 ;; In C mode C-C C-e is bound to c-macro-expand. The result of the
29 ;; expansion is put in a separate buffer. The buffer is put in 29 ;; expansion is put in a separate buffer. A user option allows the
30 ;; view-mode if the Inge Frick's view.el is installed. A user option 30 ;; window displaying the buffer to be optimally sized.
31 ;; allows the window displaying the buffer to be optimally sized.
32 ;; 31 ;;
33 ;; When called with a C-u prefix, c-macro-expand replaces the selected 32 ;; When called with a C-u prefix, c-macro-expand replaces the selected
34 ;; region with the expansion. Both the preprocessor name and the 33 ;; region with the expansion. Both the preprocessor name and the
35 ;; initial flag can be set by the user. If c-macro-prompt-p 34 ;; initial flag can be set by the user. If c-macro-prompt-flag is set
36 ;; is set to a non-nil value the user is offered to change the flags 35 ;; to a non-nil value the user is offered to change the options to the
37 ;; to the preprocessor each time c-macro-expand is invoked. 36 ;; preprocessor each time c-macro-expand is invoked. Preprocessor
38 ;; Preprocessor arguments default to the last ones entered. 37 ;; arguments default to the last ones entered. If c-macro-prompt-flag
39 ;; If c-macro-prompt is nil, one must use M-x set-variable to set a 38 ;; is nil, one must use M-x set-variable to set a different value for
40 ;; different value for c-macro-cppflags. 39 ;; c-macro-cppflags.
41 40
42 ;; A c-macro-expansion function is provided for non-interactive use. 41 ;; A c-macro-expansion function is provided for non-interactive use.
43 42
44 ;; INSTALLATION ====================================================== 43 ;; INSTALLATION ======================================================
45 44
46 ;; Put this file on your load-path, byte compile it for increased 45 ;; Put the following in your ~/.emacs file.
47 ;; speed and put part or all of the following in your ~/.emacs file. 46
48
49 ;; To make a directory ~/emacs be in front of your load-path:
50 ;;(setq load-path (cons (expand-file-name "~/emacs") load-path))
51 ;;
52 ;; Suggested keybinding (work only in c-mode):
53 ;;(if (boundp 'c-mode-map)
54 ;; (define-key c-mode-map "\C-x\C-e" 'c-macro-expand))
55 ;;(if (boundp 'c++-mode-map)
56 ;; (define-key c++-mode-map "\C-x\C-e" 'c-macro-expand))
57 ;;
58 ;; If you want the *Macroexpansion* window to be not higher than 47 ;; If you want the *Macroexpansion* window to be not higher than
59 ;; necessary: 48 ;; necessary:
60 ;;(setq c-macro-shrink-window-p t) 49 ;;(setq c-macro-shrink-window-flag t)
61 ;; 50 ;;
62 ;; If you use a preprocessor other than /lib/cpp (be careful to set a 51 ;; If you use a preprocessor other than /lib/cpp (be careful to set a
63 ;; -C option or equivalent in order to make the preprocessor not to 52 ;; -C option or equivalent in order to make the preprocessor not to
64 ;; strip the comments): 53 ;; strip the comments):
65 ;;(setq c-macro-preprocessor "gpp -C") 54 ;;(setq c-macro-preprocessor "gpp -C")
66 ;; 55 ;;
67 ;; If you often use a particular set of flags: 56 ;; If you often use a particular set of flags:
68 ;;(setq c-macro-cppflags "-I /usr/include/local -DDEBUG" 57 ;;(setq c-macro-cppflags "-I /usr/include/local -DDEBUG"
69 ;; 58 ;;
70 ;; If you want the "Preprocessor arguments: " prompt: 59 ;; If you want the "Preprocessor arguments: " prompt:
71 ;;(setq c-macro-prompt-p t) 60 ;;(setq c-macro-prompt-flag t)
72 61
73 ;; BUG REPORTS ======================================================= 62 ;; BUG REPORTS =======================================================
74 63
75 ;; Please report bugs, suggestions, complaints and so on to 64 ;; Please report bugs, suggestions, complaints and so on to
76 ;; pot@cnuce.cnr.it (Francesco Potorti`). 65 ;; pot@cnuce.cnr.it (Francesco Potorti`).
81 ;; - #line directives are inserted, so __LINE__ and __FILE__ are 70 ;; - #line directives are inserted, so __LINE__ and __FILE__ are
82 ;; correctly expanded. Works even with START inside a string, a 71 ;; correctly expanded. Works even with START inside a string, a
83 ;; comment or a region #ifdef'd away by cpp. cpp is invoked with -C, 72 ;; comment or a region #ifdef'd away by cpp. cpp is invoked with -C,
84 ;; making comments visible in the expansion. 73 ;; making comments visible in the expansion.
85 ;; - All work is done in core memory, no need for temporary files. 74 ;; - All work is done in core memory, no need for temporary files.
86 ;; - The /lib/cpp process is run synchronously. This fixes an
87 ;; infinite loop bug on Motorola Delta (cpp waiting forever for
88 ;; end-of-file, don't know why). Fixes a similar intermittent
89 ;; problem on SunOS 4.1.
90 75
91 ;; ACKNOWLEDGEMENTS ================================================== 76 ;; ACKNOWLEDGEMENTS ==================================================
92 77
93 ;; A lot of thanks to Don Maszle who did a great work of testing, bug 78 ;; A lot of thanks to Don Maszle who did a great work of testing, bug
94 ;; reporting and suggestion of new features and to Inge Fricks for her 79 ;; reporting and suggestion of new features. This work has been
95 ;; help with view.el. This work has been partially inspired by Don 80 ;; partially inspired by Don Maszle and Jonathan Segal's.
96 ;; Maszle and Jonathan Segal's.
97
98 ;; By the way, I recommend you Inge Frick's view.el. It works like
99 ;; the standard view, but *it is not recursive* and has some more
100 ;; commands. Moreover it is a minor mode, so you preserve all your
101 ;; major mode keybindings (well, not always :). Mail me to obtain a
102 ;; copy, or get it by anonymous ftp in fly.cnuce.cnr.it:pub/view.el.
103 81
104 ;; BUGS ============================================================== 82 ;; BUGS ==============================================================
105 83
106 ;; If the start point of the region is inside a macro definition the 84 ;; If the start point of the region is inside a macro definition the
107 ;; macro expansion is often inaccurate. 85 ;; macro expansion is often inaccurate.
141 (interactive "r\nP") 119 (interactive "r\nP")
142 (let ((inbuf (current-buffer)) 120 (let ((inbuf (current-buffer))
143 (displaybuf (if subst 121 (displaybuf (if subst
144 (get-buffer c-macro-buffer-name) 122 (get-buffer c-macro-buffer-name)
145 (get-buffer-create c-macro-buffer-name))) 123 (get-buffer-create c-macro-buffer-name)))
146 (expansion "") 124 (expansion ""))
147 (mymsg ""))
148 ;; Build the command string. 125 ;; Build the command string.
149 (if c-macro-prompt-flag 126 (if c-macro-prompt-flag
150 (setq c-macro-cppflags 127 (setq c-macro-cppflags
151 (read-string "Preprocessor arguments: " 128 (read-string "Preprocessor arguments: "
152 c-macro-cppflags))) 129 c-macro-cppflags)))
153 (setq mymsg (format "Invoking %s%s%s on region..."
154 c-macro-preprocessor
155 (if (string= "" c-macro-cppflags) "" " ")
156 c-macro-cppflags))
157 ;; Decide where to display output. 130 ;; Decide where to display output.
158 (if (and subst 131 (if (and subst
159 (and buffer-read-only (not inhibit-read-only)) 132 (and buffer-read-only (not inhibit-read-only))
160 (not (eq inbuf displaybuf))) 133 (not (eq inbuf displaybuf)))
161 (progn 134 (progn
164 (sit-for 2) 137 (sit-for 2)
165 (setq subst nil) 138 (setq subst nil)
166 (or displaybuf 139 (or displaybuf
167 (setq displaybuf (get-buffer-create c-macro-buffer-name))))) 140 (setq displaybuf (get-buffer-create c-macro-buffer-name)))))
168 ;; Expand the macro and output it. 141 ;; Expand the macro and output it.
169 (message mymsg)
170 (setq expansion (c-macro-expansion start end 142 (setq expansion (c-macro-expansion start end
171 (concat c-macro-preprocessor " " 143 (concat c-macro-preprocessor " "
172 c-macro-cppflags))) 144 c-macro-cppflags) t))
173 (message (concat mymsg "done"))
174 (if subst 145 (if subst
175 (let ((exchange (= (point) start))) 146 (let ((exchange (= (point) start)))
176 (delete-region start end) 147 (delete-region start end)
177 (insert expansion) 148 (insert expansion)
178 (if exchange 149 (if exchange
233 (window-height))) 204 (window-height)))
234 (goto-char (point-min)) 205 (goto-char (point-min))
235 (select-window oldwin)))))) 206 (select-window oldwin))))))
236 207
237 208
238 (defun c-macro-expansion (start end cppcommand) 209 (defun c-macro-expansion (start end cppcommand &optional display)
239 "Run a preprocessor on region and return the output as a string. 210 "Run a preprocessor on region and return the output as a string.
240 Expand the region between START and END in the current buffer using 211 Expand the region between START and END in the current buffer using
241 the shell command CPPCOMMAND (e.g. \"/lib/cpp -C -DDEBUG\"). 212 the shell command CPPCOMMAND (e.g. \"/lib/cpp -C -DDEBUG\").
242 Be sure to use a -C (don't strip comments) or equivalent option." 213 Be sure to use a -C (don't strip comments) or equivalent option.
214 Optional arg DISPLAY non-nil means show messages in the echo area."
243 215
244 ;; Copy the current buffer's contents to a temporary hidden buffer. 216 ;; Copy the current buffer's contents to a temporary hidden buffer.
245 ;; Delete from END to end of buffer. Insert a preprocessor #line 217 ;; Delete from END to end of buffer. Insert a preprocessor #line
246 ;; directive at START and after each #endif following START that are 218 ;; directive at START and after each #endif following START that are
247 ;; not inside a comment or a string. Put all the strings thus 219 ;; not inside a comment or a string. Put all the strings thus
257 (filename (if (and buffer-file-name 229 (filename (if (and buffer-file-name
258 (string-match (regexp-quote default-directory) 230 (string-match (regexp-quote default-directory)
259 buffer-file-name)) 231 buffer-file-name))
260 (substring buffer-file-name (match-end 0)) 232 (substring buffer-file-name (match-end 0))
261 (buffer-name))) 233 (buffer-name)))
262 (start-state) 234 (mymsg (format "Invoking %s%s%s on region..."
235 c-macro-preprocessor
236 (if (string= "" c-macro-cppflags) "" " ")
237 c-macro-cppflags))
238 (uniquestring "???!!!???!!! start of c-macro expansion ???!!!???!!!")
239 (startlinenum 0)
263 (linenum 0) 240 (linenum 0)
264 (linelist ())) 241 (startstat ())
242 (startmarker ""))
265 (unwind-protect 243 (unwind-protect
266 (save-excursion 244 (save-excursion
267 (save-restriction 245 (save-restriction
268 (widen) 246 (widen)
269 (set-buffer outbuf) 247 (set-buffer outbuf)
273 (insert-buffer-substring inbuf 1 end)) 251 (insert-buffer-substring inbuf 1 end))
274 252
275 ;; We have copied inbuf to outbuf. Point is at end of 253 ;; We have copied inbuf to outbuf. Point is at end of
276 ;; outbuf. Insert a space at the end, so cpp can correctly 254 ;; outbuf. Insert a space at the end, so cpp can correctly
277 ;; parse a token ending at END. 255 ;; parse a token ending at END.
278
279 (insert " ") 256 (insert " ")
280 257
281 (save-excursion 258 ;; Save sexp status and line number at START.
282 (goto-char start) 259 (setq startstat (parse-partial-sexp 1 start))
283 (setq start-state (parse-partial-sexp 1 (point)))) 260 (setq startlinenum (+ (count-lines 1 (point))
261 (if (bolp) 1 0)))
262
284 ;; Now we insert the #line directives after all #endif or 263 ;; Now we insert the #line directives after all #endif or
285 ;; #else following START. 264 ;; #else following START going backward, so the lines we
265 ;; insert don't change the line numbers.
286 ;(switch-to-buffer outbuf) (debug) ;debugging instructions 266 ;(switch-to-buffer outbuf) (debug) ;debugging instructions
267 (goto-char (point-max))
287 (while (re-search-backward "\n#\\(endif\\|else\\)\\>" start 'move) 268 (while (re-search-backward "\n#\\(endif\\|else\\)\\>" start 'move)
288 (if (equal (nthcdr 3 (parse-partial-sexp start (point) start-state)) 269 (if (equal (nthcdr 3 (parse-partial-sexp start (point)
270 nil nil startstat))
289 '(nil nil nil 0 nil)) ;neither in string nor in 271 '(nil nil nil 0 nil)) ;neither in string nor in
290 ;comment nor after quote 272 ;comment nor after quote
291 (progn 273 (progn
292 (goto-char (match-end 0)) 274 (goto-char (match-end 0))
293 ;;; (setq linenum (count-lines 1 (point))) 275 (setq linenum (+ startlinenum
294 (setq linelist 276 (count-lines start (point))))
295 ;; This used to be a #line command 277 (insert (format "\n#line %d \"%s\"\n" linenum filename))
296 ;; but it's not guaranteed that the output 278 (goto-char (match-beginning 0)))))
297 ;; will have properly matching commands. 279
298 ;; Only the *line numbers* have to agree! 280 ;; Now we are at START. Insert the first #line directive.
299 (cons (format "\n???!!!???!!!!\n") 281 ;; This must work even inside a string or comment, or after a
300 linelist))
301 (insert (car linelist))
302 (skip-chars-backward "^#")
303 (insert "line")
304 (goto-char (match-beginning 0)))))
305
306 ;; We are at START. Insert the first #line directive. This
307 ;; must work even inside a string or comment, or after a
308 ;; quote. 282 ;; quote.
309 ;;; (setq linenum (+ (count-lines 1 (point)) 283 (let* ((startinstring (nth 3 startstat))
310 ;;; (if (bolp) 1 0))) 284 (startincomment (nth 4 startstat))
311 (setq linelist 285 (startafterquote (nth 5 startstat))
312 (cons 286 (startinbcomment (nth 7 startstat)))
313 (let* ((startstat (parse-partial-sexp 1 start)) 287 (insert (if startafterquote " " "")
314 (startinstring (nth 3 startstat)) 288 (cond (startinstring
315 (startincomment (nth 4 startstat)) 289 (char-to-string startinstring))
316 (startafterquote (nth 5 startstat)) 290 (startincomment "*/")
317 (startinbcomment (nth 6 startstat))) 291 (""))
318 (concat (if startafterquote " ") 292 (format "\n#line %d \"%s\"\n" startlinenum filename)
319 (cond (startinstring (char-to-string startinstring)) 293 (setq startmarker
320 (startincomment "*/")) 294 (concat uniquestring
321 (format "\n???!!!???!!!!") 295 (cond (startinstring
322 (cond (startinstring (char-to-string startinstring)) 296 (char-to-string startinstring))
323 (startincomment "/*") 297 (startincomment "/*")
324 (startinbcomment "//")) 298 (startinbcomment "//"))
325 (if startafterquote "\\"))) 299 (if startafterquote "\\")))))
326 linelist))
327 (insert (car linelist))
328 (skip-chars-backward "^#")
329 (insert "line")
330 300
331 ;; Call the preprocessor. 301 ;; Call the preprocessor.
302 (if display (message mymsg))
332 (call-process-region 1 (point-max) "sh" t t nil "-c" 303 (call-process-region 1 (point-max) "sh" t t nil "-c"
333 (concat cppcommand " 2>/dev/null")) 304 (concat cppcommand " 2>/dev/null"))
334 305 (if display (message (concat mymsg "done")))
335 (while (search-backward "\n???!!!???!!!!" nil t) 306
336 (replace-match "")) 307 ;; Find and delete the mark of the start of the expansion.
337 308 ;; Look for `# nn "file.c"' lines and delete them.
309 (goto-char (point-min))
310 (search-forward startmarker)
311 (delete-region 1 (point))
312 (while (re-search-forward (concat "^# [0-9]+ \""
313 (regexp-quote filename)
314 "\"") nil t)
315 (beginning-of-line)
316 (let ((beg (point)))
317 (forward-line 1)
318 (delete-region beg (point))))
319
338 ;; Compute the return value, keeping in account the space 320 ;; Compute the return value, keeping in account the space
339 ;; inserted at the end of the buffer. 321 ;; inserted at the end of the buffer.
340 (buffer-substring (point) (max (point) (- (point-max) 1)))) 322 (buffer-substring 1 (max 1 (- (point-max) 1))))
341 323
342 ;; Cleanup. 324 ;; Cleanup.
343 (kill-buffer outbuf)))) 325 (kill-buffer outbuf))))
344 326
345 ;;; cmacexp.el ends here 327 ;;; cmacexp.el ends here