aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond1993-04-08 16:35:48 +0000
committerEric S. Raymond1993-04-08 16:35:48 +0000
commitee0155df12d8b26fcf8f690535b08386ec86e524 (patch)
treed639a1ba22a69ee78c01c46566e4d321b263437b
parent235aa29bda408d144ba409e572daa557dc9c6f57 (diff)
downloademacs-ee0155df12d8b26fcf8f690535b08386ec86e524.tar.gz
emacs-ee0155df12d8b26fcf8f690535b08386ec86e524.zip
Massive changes, amounting nearly to a rewrite. The new features
include auto-configuring support for SVr4, more commands, and a full minor-mode implementation that binds all GUD commands not just in the GUD interaction mode, but in C buffers visited by GUD. The common prefix of GUD commands is now C-x X, like electric-debug mode.
-rw-r--r--lisp/gud.el807
1 files changed, 513 insertions, 294 deletions
diff --git a/lisp/gud.el b/lisp/gud.el
index 13e510d8d55..fc30025ff00 100644
--- a/lisp/gud.el
+++ b/lisp/gud.el
@@ -1,10 +1,9 @@
1;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, or dbx under Emacs 1;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, or dbx under Emacs
2 2
3;; Author: Eric S. Raymond <eric@snark.thyrsus.com> 3;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
4;; Version: 1.1
4;; Keywords: unix, tools 5;; Keywords: unix, tools
5 6
6;; %W%
7
8;; Copyright (C) 1992 Free Software Foundation, Inc. 7;; Copyright (C) 1992 Free Software Foundation, Inc.
9 8
10;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -31,14 +30,25 @@
31;; The overloading code was then rewritten by Barry Warsaw <bwarsaw@cen.com>, 30;; The overloading code was then rewritten by Barry Warsaw <bwarsaw@cen.com>,
32;; who also hacked the mode to use comint.el. 31;; who also hacked the mode to use comint.el.
33 32
34;; Note: use of this package with sdb requires that your tags.el support 33;; This code will not work under Emacs 18. It relies on Emacs 19's
35;; the find-tag-noselect entry point. Stock distributions up to 18.57 do 34;; minor-mode-keymap support and the find-tag-noselect entry point of etags.
36;; *not* include this feature; if it's not included with this file, email 35
37;; esr@snark.thyrsus.com for it or get 18.58. 36;;; Change Log:
38 37
39;; Further note: due to lossage in the Emacs-18 byte compiler, compiled 38;; Version 1.1: ESR 6 Apr 1993
40;; versions of this code will fail with a complaint about gud-step if 39;; * Facility to accept and parse command-line switches other than the
41;; you invoke the gdb or sdb initializers. This should be fixed in 19. 40;; filename added.
41;; * System V Release 4 support added.
42;; * Can now set temporary breakpoints in sdb.
43;; * A GUD minor mode using the 19 minor-mode-keymap facilities is now
44;; enabled in visited C buffers.
45;; * Command bindings are now automatically the same in gud-minor-mode
46;; as they are in the GUD buffer itself, and use ^XX as a common
47;; prefix (for compatibility with electric-debug).
48;; * There is a new command for printing the C expression around point.
49
50;; Version 1.0: ESR
51;; * Created.
42 52
43;;; Code: 53;;; Code:
44 54
@@ -46,6 +56,42 @@
46(require 'etags) 56(require 'etags)
47 57
48;; ====================================================================== 58;; ======================================================================
59;; minor-mode machinery for C buffers visited by GUD
60
61(defvar gud-key-prefix "\C-xX"
62 "Prefix of all GUD minor-mode commands valid in C buffers.")
63
64(defvar gud-minor-mode nil)
65(or (assq 'gud-minor-mode minor-mode-alist)
66 (setq minor-mode-alist
67 (cons '(gud-minor-mode " GUD") minor-mode-alist)))
68
69(defvar gud-mode-map nil)
70(if gud-mode-map
71 nil
72 (setq gud-mode-map (make-sparse-keymap))
73 (define-key gud-mode-map gud-key-prefix (make-sparse-keymap))
74 (define-key gud-mode-map (concat gud-key-prefix "\C-l") 'gud-refresh)
75 )
76
77(or (assq 'gud-minor-mode minor-mode-map-alist)
78 (setq minor-mode-map-alist
79 (cons
80 (cons 'gud-minor-mode gud-mode-map)
81 minor-mode-map-alist)))
82
83(defun gud-minor-mode (&optional enable)
84 "GUD minor mode is enabled in C buffers visited due to a GUD stop at
85breakpoint. All GUD-specific commands defined in GUD major mode will work,
86but they get their current file and current line number from the context of
87this buffer."
88 (interactive "P")
89 (setq gud-minor-mode
90 (if (null enable) (not gud-minor-mode)
91 (> (prefix-numeric-value enable) 0)))
92)
93
94;; ======================================================================
49;; the overloading mechanism 95;; the overloading mechanism
50 96
51(defun gud-overload-functions (gud-overload-alist) 97(defun gud-overload-functions (gud-overload-alist)
@@ -56,17 +102,17 @@ This association list has elements of the form
56 (function (lambda (p) (fset (car p) (symbol-function (cdr p))))) 102 (function (lambda (p) (fset (car p) (symbol-function (cdr p)))))
57 gud-overload-alist)) 103 gud-overload-alist))
58 104
59(defun gud-debugger-startup (f d) 105(defun gud-debugger-startup (file args)
60 (error "GUD not properly entered.")) 106 (error "GUD not properly entered."))
61 107
62(defun gud-marker-filter (proc s) 108(defun gud-marker-filter (str)
63 (error "GUD not properly entered.")) 109 (error "GUD not properly entered."))
64 110
65(defun gud-visit-file (f) 111(defun gud-find-file (f)
66 (error "GUD not properly entered.")) 112 (error "GUD not properly entered."))
67 113
68(defun gud-set-break (proc f n rest) 114;; ======================================================================
69 (error "GUD not properly entered.")) 115;; command definition
70 116
71;; This macro is used below to define some basic debugger interface commands. 117;; This macro is used below to define some basic debugger interface commands.
72;; Of course you may use `gud-def' with any other debugger command, including 118;; Of course you may use `gud-def' with any other debugger command, including
@@ -74,29 +120,46 @@ This association list has elements of the form
74 120
75;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form 121;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form
76;; which defines FUNC to send the command NAME to the debugger, gives 122;; which defines FUNC to send the command NAME to the debugger, gives
77;; it the docstring DOC, and binds that function to KEY. NAME should 123;; it the docstring DOC, and binds that function to KEY in the GUD
78;; be a string. If a numeric prefix argument is given to FUNC, it 124;; major mode. The function is also bound in the GUD minor-mode
79;; gets sent after NAME. 125;; keymap. If a numeric prefix argument is given to FUNC, it gets
80 126;; sent after NAME.
81(defmacro gud-def (func name key &optional doc) 127
82 (let* ((cstr (list 'if '(not (= 1 arg)) 128(defmacro gud-def (func cmd key &optional doc)
83 (list 'format "%s %s" name 'arg) 129 "Define FUNC to be a command sending STR and bound to KEY, with
84 name))) 130optional doc string DOC. Certain %-escapes in the string arguments
85 (list 'progn 131are interpreted specially if present. These are:
86 (list 'defun func '(arg) 132
87 (or doc "") 133 %f name of current source file.
88 '(interactive "p") 134 %l number of current source line
89 (list 'gud-call cstr)) 135 %e text of the C lvalue or function-call expression surrounding point.
90 (if key 136 %a text of the hexadecimal address surrounding point
91 (list 'define-key 'gud-mode-map key (list 'quote func)))))) 137 %p prefix argument to the command (if any) as a number
138
139 The `current' source file is the file of the current buffer (if we're in a
140C file with gud-minor-mode active) or the source file current at the last
141break or step (if we're in the GUD buffer).
142 The `current' line is that of the current buffer (if we're in a source
143file with gud-minor-mode active) or the source line number at the last
144break or step (if we're in the GUD buffer)."
145 (list 'progn
146 (list 'defun func '(arg)
147 (or doc "")
148 '(interactive "p")
149 (list 'gud-call cmd 'arg))
150 (if key
151 (list 'define-key
152 'gud-mode-map
153 (concat gud-key-prefix key)
154 (list 'quote func)))))
92 155
93;; Where gud-display-frame should put the debugging arrow. This is 156;; Where gud-display-frame should put the debugging arrow. This is
94;; set by the marker-filter, which scans the debugger's output for 157;; set by the marker-filter, which scans the debugger's output for
95;; indications of the current pc. 158;; indications of the current program counter.
96(defvar gud-last-frame nil) 159(defvar gud-last-frame nil)
97 160
98;; All debugger-specific information is collected here 161;; All debugger-specific information is collected here.
99;; Here's how it works, in case you ever need to add a debugger to the table. 162;; Here's how it works, in case you ever need to add a debugger to the mode.
100;; 163;;
101;; Each entry must define the following at startup: 164;; Each entry must define the following at startup:
102;; 165;;
@@ -104,11 +167,10 @@ This association list has elements of the form
104;; comint-prompt-regexp 167;; comint-prompt-regexp
105;; gud-<name>-debugger-startup 168;; gud-<name>-debugger-startup
106;; gud-<name>-marker-filter 169;; gud-<name>-marker-filter
107;; gud-<name>-visit-file 170;; gud-<name>-find-file
108;; gud-<name>-set-break
109;; 171;;
110;; The job of the startup-command method is to fire up a copy of the debugger, 172;; The job of the startup-command method is to fire up a copy of the debugger,
111;; given an object file and source directory. 173;; given a list of debugger arguments.
112;; 174;;
113;; The job of the marker-filter method is to detect file/line markers in 175;; The job of the marker-filter method is to detect file/line markers in
114;; strings and set the global gud-last-frame to indicate what display 176;; strings and set the global gud-last-frame to indicate what display
@@ -117,26 +179,17 @@ This association list has elements of the form
117;; can filter the debugger's output, interpreting some and passing on 179;; can filter the debugger's output, interpreting some and passing on
118;; the rest. 180;; the rest.
119;; 181;;
120;; The job of the visit-file method is to visit and return the buffer indicated 182;; The job of the find-file method is to visit and return the buffer indicated
121;; by the car of gud-tag-frame. This may be a file name, a tag name, or 183;; by the car of gud-tag-frame. This may be a file name, a tag name, or
122;; something else. 184;; something else.
123;;
124;; The job of the gud-set-break method is to send the commands
125;; necessary to set a breakpoint at a given line in a given source
126;; file. If its third argument TEMP is non-nil, the breakpoint set
127;; should be temporary - it should be deleted when it is reached. If
128;; the debugger doesn't support such breakpoints, it should set an
129;; ordinary breakpoint.
130;;
131;; Debugger-specific information begins here:
132 185
133;; ====================================================================== 186;; ======================================================================
134;; gdb functions 187;; gdb functions
135 188
136(defun gud-gdb-debugger-startup (f d) 189(defun gud-gdb-debugger-startup (file args)
137 (make-comint (concat "gud-" f) "gdb" nil "-fullname" "-cd" d f)) 190 (apply 'make-comint (concat "gud-" file) "gdb" nil "-fullname" args))
138 191
139(defun gud-gdb-marker-filter (proc string) 192(defun gud-gdb-marker-filter (string)
140 (if (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" string) 193 (if (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" string)
141 (progn 194 (progn
142 (setq gud-last-frame 195 (setq gud-last-frame
@@ -152,33 +205,33 @@ This association list has elements of the form
152 )) 205 ))
153 string)) 206 string))
154 207
155(defun gud-gdb-visit-file (f) 208(defun gud-gdb-find-file (f)
156 (find-file-noselect f)) 209 (find-file-noselect f))
157 210
158(defun gud-gdb-set-break (proc f n temp)
159 (gud-call "%s %s:%d" (if temp "tbreak" "break") f n))
160
161;;;###autoload 211;;;###autoload
162(defun gdb (path) 212(defun gdb (args)
163 "Run gdb on program FILE in buffer *gud-FILE*. 213 "Run gdb on program FILE in buffer *gud-FILE*.
164The directory containing FILE becomes the initial working directory 214The directory containing FILE becomes the initial working directory
165and source-file directory for your debugger." 215and source-file directory for your debugger."
166 (interactive "fRun gdb on file: ") 216 (interactive "sgdb ")
167 (gud-overload-functions '((gud-debugger-startup . gud-gdb-debugger-startup) 217 (gud-overload-functions '((gud-debugger-startup . gud-gdb-debugger-startup)
168 (gud-marker-filter . gud-gdb-marker-filter) 218 (gud-marker-filter . gud-gdb-marker-filter)
169 (gud-visit-file . gud-gdb-visit-file) 219 (gud-find-file . gud-gdb-find-file)
170 (gud-set-break . gud-gdb-set-break))) 220 ))
171 221
172 (gud-def gud-step "step" "\C-c\C-s" "Step one source line with display") 222 (gud-def gud-break "break %f:%l" "b" "Set breakpoint at current line.")
173 (gud-def gud-stepi "stepi" "\C-c\C-i" "Step one instruction with display") 223 (gud-def gud-tbreak "tbreak %f:%l" "t" "Set breakpoint at current line.")
174 (gud-def gud-next "next" "\C-c\C-n" "Step one line (skip functions)") 224 (gud-def gud-remove "clear %l" "d" "Remove breakpoint at current line")
175 (gud-def gud-cont "cont" "\C-c\C-r" "Continue with display") 225 (gud-def gud-step "step %p" "s" "Step one source line with display.")
176 226 (gud-def gud-stepi "stepi %p" "i" "Step one instruction with display.")
177 (gud-def gud-finish "finish" "\C-c\C-f" "Finish executing current function") 227 (gud-def gud-next "next %p" "n" "Step one line (skip functions).")
178 (gud-def gud-up "up" "\C-c<" "Up N stack frames (numeric arg)") 228 (gud-def gud-cont "cont" "r" "Continue with display.")
179 (gud-def gud-down "down" "\C-c>" "Down N stack frames (numeric arg)") 229 (gud-def gud-finish "finish" "f" "Finish executing current function.")
180 230 (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
181 (gud-common-init path) 231 (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
232 (gud-def gud-print "print %e" "p" "Evaluate C expression at point.")
233
234 (gud-common-init args)
182 235
183 (setq comint-prompt-regexp "^(.*gdb[+]?) *") 236 (setq comint-prompt-regexp "^(.*gdb[+]?) *")
184 (run-hooks 'gdb-mode-hook) 237 (run-hooks 'gdb-mode-hook)
@@ -188,47 +241,68 @@ and source-file directory for your debugger."
188;; ====================================================================== 241;; ======================================================================
189;; sdb functions 242;; sdb functions
190 243
191(defun gud-sdb-debugger-startup (f d) 244(defvar gud-sdb-needs-tags (not (file-exists-p "/var"))
192 (make-comint (concat "gud-" f) "sdb" nil f "-" d)) 245 "If nil, we're on a System V Release 4 and don't need the tags hack.")
246
247(defvar gud-sdb-lastfile nil)
248
249(defun gud-sdb-debugger-startup (file args)
250 (apply 'make-comint (concat "gud-" file) "sdb" nil args))
193 251
194(defun gud-sdb-marker-filter (proc string) 252(defun gud-sdb-marker-filter (string)
195 (if (string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n" 253 (cond
254 ;; System V Release 3.2 uses this format
255 ((string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n"
196 string) 256 string)
197 (setq gud-last-frame 257 (setq gud-last-frame
198 (cons 258 (cons
199 (substring string (match-beginning 2) (match-end 2)) 259 (substring string (match-beginning 2) (match-end 2))
200 (string-to-int 260 (string-to-int
201 (substring string (match-beginning 3) (match-end 3)))))) 261 (substring string (match-beginning 3) (match-end 3))))))
262 ;; System V Release 4.0
263 ((string-match "^\\(BREAKPOINT\\|STEPPED\\) process [0-9]+ function [^ ]+ in \\(.+\\)\n"
264 string)
265 (setq gud-sdb-lastfile
266 (substring string (match-beginning 2) (match-end 2))))
267 ((and gud-sdb-lastfile (string-match "^\\([0-9]+\\):" string))
268 (setq gud-last-frame
269 (cons
270 gud-sdb-lastfile
271 (string-to-int
272 (substring string (match-beginning 1) (match-end 1))))))
273 (t
274 (setq gud-sdb-lastfile nil)))
202 string) 275 string)
203 276
204(defun gud-sdb-visit-file (f) 277(defun gud-sdb-find-file (f)
205 (find-tag-noselect f)) 278 (if gud-sdb-needs-tags
206 279 (find-tag-noselect f)
207;;; We'll just ignore the TEMP argument for now; I don't know how to 280 (find-file-noselect f)))
208;;; set temporary breakpoints in sdb. (See the description of the
209;;; gud-set-break method for details.)
210(defun gud-sdb-set-break (proc f n temp)
211 (gud-queue-send (format "e %s" f) (format "%d b" n)))
212 281
213;;;###autoload 282;;;###autoload
214(defun sdb (path) 283(defun sdb (args)
215 "Run sdb on program FILE in buffer *gud-FILE*. 284 "Run sdb on program FILE in buffer *gud-FILE*.
216The directory containing FILE becomes the initial working directory 285The directory containing FILE becomes the initial working directory
217and source-file directory for your debugger." 286and source-file directory for your debugger."
218 (interactive "fRun sdb on file: ") 287 (interactive "ssdb ")
219 (if (not (and (boundp 'tags-file-name) (file-exists-p tags-file-name))) 288 (if (and gud-sdb-needs-tags
289 (not (and (boundp 'tags-file-name) (file-exists-p tags-file-name))))
220 (error "The sdb support requires a valid tags table to work.")) 290 (error "The sdb support requires a valid tags table to work."))
221 (gud-overload-functions '((gud-debugger-startup . gud-sdb-debugger-startup) 291 (gud-overload-functions '((gud-debugger-startup . gud-sdb-debugger-startup)
222 (gud-marker-filter . gud-sdb-marker-filter) 292 (gud-marker-filter . gud-sdb-marker-filter)
223 (gud-visit-file . gud-sdb-visit-file) 293 (gud-find-file . gud-sdb-find-file)
224 (gud-set-break . gud-sdb-set-break))) 294 ))
225 295
226 (gud-def gud-step "s" "\C-c\C-s" "Step one source line with display") 296 (gud-def gud-break "%l b" "b" "Set breakpoint at current line.")
227 (gud-def gud-stepi "i" "\C-c\C-i" "Step one instruction with display") 297 (gud-def gud-tbreak "%l c" "t" "Set temporary breakpoint at current line.")
228 (gud-def gud-next "S" "\C-c\C-n" "Step one source line (skip functions)") 298 (gud-def gud-remove "%l d" "d" "Remove breakpoint at current line")
229 (gud-def gud-cont "c" "\C-c\C-r" "Continue with display (`resume')") 299 (gud-def gud-step "s %p" "s" "Step one source line with display.")
300 (gud-def gud-stepi "i %p" "i" "Step one instruction with display.")
301 (gud-def gud-next "S %p" "n" "Step one line (skip functions).")
302 (gud-def gud-cont "c" "r" "Continue with display.")
303 (gud-def gud-print "%e/" "p" "Evaluate C expression at point.")
230 304
231 (gud-common-init path) 305 (gud-common-init args)
232 306
233 (setq comint-prompt-regexp "\\(^\\|\n\\)\\*") 307 (setq comint-prompt-regexp "\\(^\\|\n\\)\\*")
234 (run-hooks 'sdb-mode-hook) 308 (run-hooks 'sdb-mode-hook)
@@ -237,10 +311,10 @@ and source-file directory for your debugger."
237;; ====================================================================== 311;; ======================================================================
238;; dbx functions 312;; dbx functions
239 313
240(defun gud-dbx-debugger-startup (f d) 314(defun gud-dbx-debugger-startup (file args)
241 (make-comint (concat "gud-" f) "dbx" nil f)) 315 (apply 'make-comint (concat "gud-" file) "dbx" nil args))
242 316
243(defun gud-dbx-marker-filter (proc string) 317(defun gud-dbx-marker-filter (string)
244 (if (string-match 318 (if (string-match
245 "stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" string) 319 "stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" string)
246 (setq gud-last-frame 320 (setq gud-last-frame
@@ -250,35 +324,32 @@ and source-file directory for your debugger."
250 (substring string (match-beginning 1) (match-end 1)))))) 324 (substring string (match-beginning 1) (match-end 1))))))
251 string) 325 string)
252 326
253(defun gud-dbx-visit-file (f) 327(defun gud-dbx-find-file (f)
254 (find-file-noselect f)) 328 (find-file-noselect f))
255 329
256;;; We'll just ignore the TEMP argument for now; I don't know how to
257;;; set temporary breakpoints in dbx. (See the description of the
258;;; gud-set-break method for details.)
259(defun gud-dbx-set-break (proc f n temp)
260 (gud-call "stop at \"%s\":%d" f n))
261
262;;;###autoload 330;;;###autoload
263(defun dbx (path) 331(defun dbx (args)
264 "Run dbx on program FILE in buffer *gud-FILE*. 332 "Run dbx on program FILE in buffer *gud-FILE*.
265The directory containing FILE becomes the initial working directory 333The directory containing FILE becomes the initial working directory
266and source-file directory for your debugger." 334and source-file directory for your debugger."
267 (interactive "fRun dbx on file: ") 335 (interactive "sdbx")
268 (gud-overload-functions '((gud-debugger-startup . gud-dbx-debugger-startup) 336 (gud-overload-functions '((gud-debugger-startup . gud-dbx-debugger-startup)
269 (gud-marker-filter . gud-dbx-marker-filter) 337 (gud-marker-filter . gud-dbx-marker-filter)
270 (gud-visit-file . gud-dbx-visit-file) 338 (gud-find-file . gud-dbx-find-file)
271 (gud-set-break . gud-dbx-set-break))) 339 ))
272 340
273 (gud-def gud-step "step" "\C-c\C-s" "Step one source line with display") 341 (gud-def gud-break "stop at \"%f\":%l"
274 (gud-def gud-stepi "stepi" "\C-c\C-i" "Step one instruction with display") 342 "b" "Set breakpoint at current line.")
275 (gud-def gud-next "next" "\C-c\C-n" "Step one line (skip functions)") 343 (gud-def gud-remove "clear %l" "d" "Remove breakpoint at current line")
276 (gud-def gud-cont "cont" "\C-c\C-r" "Continue with display (`resume')") 344 (gud-def gud-step "step %p" "s" "Step one line with display.")
277 345 (gud-def gud-stepi "stepi %p" "i" "Step one instruction with display.")
278 (gud-def gud-up "up" "\C-c<" "Up N stack frames (numeric arg)") 346 (gud-def gud-next "next %p" "n" "Step one line (skip functions).")
279 (gud-def gud-down "down" "\C-c>" "Down N stack frames (numeric arg)") 347 (gud-def gud-cont "cont" "r" "Continue with display.")
280 348 (gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.")
281 (gud-common-init path) 349 (gud-def gud-down "down %p" ">" "Down (numeric arg) stack frames.")
350 (gud-def gud-print "print %e" "p" "Evaluate C expression at point.")
351
352 (gud-common-init args)
282 (setq comint-prompt-regexp "^[^)]*dbx) *") 353 (setq comint-prompt-regexp "^[^)]*dbx) *")
283 354
284 (run-hooks 'dbx-mode-hook) 355 (run-hooks 'dbx-mode-hook)
@@ -288,15 +359,6 @@ and source-file directory for your debugger."
288;; End of debugger-specific information 359;; End of debugger-specific information
289;; 360;;
290 361
291(defvar gud-mode-map nil
292 "Keymap for gud-mode.")
293
294(defvar gud-commands nil
295 "List of strings or functions used by send-gud-command.
296It is for customization by you.")
297
298(defvar gud-command-queue nil)
299
300;;; When we send a command to the debugger via gud-call, it's annoying 362;;; When we send a command to the debugger via gud-call, it's annoying
301;;; to see the command and the new prompt inserted into the debugger's 363;;; to see the command and the new prompt inserted into the debugger's
302;;; buffer; we have other ways of knowing the command has completed. 364;;; buffer; we have other ways of knowing the command has completed.
@@ -339,15 +401,6 @@ It is for customization by you.")
339;;; prompt alone. 401;;; prompt alone.
340(defvar gud-delete-prompt-marker nil) 402(defvar gud-delete-prompt-marker nil)
341 403
342(if gud-mode-map
343 nil
344 (setq gud-mode-map (copy-keymap comint-mode-map))
345 (define-key gud-mode-map "\C-c\C-l" 'gud-refresh))
346
347;; Global mappings --- we'll invoke these from a source buffer.
348(define-key ctl-x-map " " 'gud-break)
349(define-key ctl-x-map "&" 'send-gud-command)
350
351 404
352(defun gud-mode () 405(defun gud-mode ()
353 "Major mode for interacting with an inferior debugger process. 406 "Major mode for interacting with an inferior debugger process.
@@ -356,52 +409,56 @@ It is for customization by you.")
356M-x dbx. Each entry point finishes by executing a hook; gdb-mode-hook, 409M-x dbx. Each entry point finishes by executing a hook; gdb-mode-hook,
357sdb-mode-hook or dbx-mode-hook respectively. 410sdb-mode-hook or dbx-mode-hook respectively.
358 411
359After startup, the following commands are available: 412After startup, the following commands are available in both the GUD
413interaction buffer and any source buffer GUD visits due to a breakpoint stop
414or step operation:
360 415
361\\{gud-mode-map} 416\\{gud-mode-map}
362 417
363\\[gud-refresh] displays in the other window the last line referred to 418\\[gud-break] sets a breakpoint at the current file and line. In the
419GUD buffer, the current file and line are those of the last breakpoint or
420step. In a source buffer, they are the buffer's file and current line.
421
422\\[gud-refresh] displays in the source window the last line referred to
364in the gud buffer. 423in the gud buffer.
365 424
366\\[gud-step], \\[gud-next], and \\[gud-stepi] in the gud window, 425\\[gud-step], \\[gud-next], and \\[gud-stepi] do a step-one-line,
367do a step-one-line, step-one-line (not entering function calls), and 426step-one-line (not entering function calls), and step-one-instruction
368step-one-instruction and then update the other window 427and then update the source window with the current file and position.
369with the current file and position. \\[gud-cont] continues 428\\[gud-cont] continues execution.
370execution.
371 429
372The above commands are common to all supported debuggers. If you are 430\\[gud-print] tries to find the largest C lvalue or function-call expression
373using gdb or dbx, the following additional commands will be available: 431around point, and sends it to the debugger for value display.
374 432
375\\[gud-up] pops up through an enclosing stack frame. \\[gud-down] drops 433The above commands are common to all supported debuggers.
376back down through one.
377 434
378If you are using gdb, \\[gdb-finish] runs execution to the return from 435Under gdb and sdb, \\[gud-tbreak] behaves exactly like \\[gud-break],
379the current function and stops. 436except that the breakpoint is temporary; that is, it is removed when
437execution stops on it.
380 438
381These functions repeat themselves the appropriate number of times if you give a 439Under gdb and dbx, \\[gud-up] pops up through an enclosing stack
382prefix argument. 440frame. \\[gud-down] drops back down through one.
383 441
384If you are in a source file, you may do the following: 442If you are using gdb, \\[gdb-finish] runs execution to the return from
443the current function and stops.
385 444
386Set a breakpoint at the current line by doing \\[gud-break]. This causes 445All pre-defined functions for which the concept make sense repeat
387an appropriate set-break to be send to the debugger; of course, if the file 446themselves the appropriate number of times if you give a prefix
388you're visiting doesn't correspond to any code in the executable this will 447argument.
389have no effect or raise an error.
390 448
391Execute a user-defined command at point with \\[send-gud-command]; the 449You may use the gud-def macro in the initialization hook to define other
392prefix argument is taken as an index into the list of strings gud-commands. 450commands.
393A %s in a gud-commands string is substituted with a number or address picked
394up from point.
395 451
396Other commands for interacting with the debugger process are inherited from 452Other commands for interacting with the debugger process are inherited from
397comint mode, which see." 453comint mode, which see."
398 (interactive) 454 (interactive)
399 (comint-mode) 455 (comint-mode)
400; (kill-all-local-variables)
401 (setq major-mode 'gud-mode) 456 (setq major-mode 'gud-mode)
402 (setq mode-name "Debugger") 457 (setq mode-name "Debugger")
403 (setq mode-line-process '(": %s")) 458 (setq mode-line-process '(": %s"))
404 (use-local-map gud-mode-map) 459 (use-local-map (copy-keymap comint-mode-map))
460 (define-key (current-local-map)
461 gud-key-prefix (lookup-key gud-mode-map gud-key-prefix))
405 (make-local-variable 'gud-last-frame) 462 (make-local-variable 'gud-last-frame)
406 (setq gud-last-frame nil) 463 (setq gud-last-frame nil)
407 (make-local-variable 'comint-prompt-regexp) 464 (make-local-variable 'comint-prompt-regexp)
@@ -410,78 +467,87 @@ comint mode, which see."
410 (run-hooks 'gud-mode-hook) 467 (run-hooks 'gud-mode-hook)
411) 468)
412 469
413(defvar current-gud-buffer nil) 470(defvar gud-comint-buffer nil)
414 471
415(defun gud-common-init (path) 472(defun gud-common-init (args)
416 ;; perform initializations common to all debuggers 473 ;; Perform initializations common to all debuggers
417 (setq path (expand-file-name path)) 474 ;; There *must* be a cleaner way to lex the arglist...
418 (let ((file (file-name-nondirectory path))) 475 (let (file i)
419 (switch-to-buffer (concat "*gud-" file "*")) 476 (if (string= args "")
420 (setq default-directory (file-name-directory path)) 477 (setq args nil)
421 (or (bolp) (newline)) 478 (set-buffer (get-buffer-create "*gud-scratch*"))
422 (insert "Current directory is " default-directory "\n") 479 (erase-buffer)
423 (gud-debugger-startup file default-directory)) 480 (insert args)
481 (goto-char (point-max))
482 (insert "\")")
483 (goto-char (point-min))
484 (insert "(\"")
485 (while (re-search-forward " +" nil t)
486 (replace-match "\" \"" nil nil))
487 (goto-char (point-min))
488 (while (re-search-forward "\"\"" nil t)
489 (replace-match "" nil nil))
490 (setq args (read (buffer-string)))
491 (kill-buffer (current-buffer)))
492 (setq i (1- (length args)))
493 (while (and (>= i 0) (not (= (aref (nth i args) 0) ?-)))
494 (setq file (nth i args)) (setq i (1- i)))
495 (let* ((path (expand-file-name file))
496 (filepart (file-name-nondirectory path)))
497 (switch-to-buffer (concat "*gud-" filepart "*"))
498 (setq default-directory (file-name-directory path))
499 (or (bolp) (newline))
500 (insert "Current directory is " default-directory "\n")
501 (gud-debugger-startup filepart args)))
424 (gud-mode) 502 (gud-mode)
425 (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) 503 (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter)
426 (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel) 504 (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel)
427 (setq gud-command-queue nil)
428 (gud-set-buffer) 505 (gud-set-buffer)
429 ) 506 )
430 507
431(defun gud-set-buffer () 508(defun gud-set-buffer ()
432 (cond ((eq major-mode 'gud-mode) 509 (cond ((eq major-mode 'gud-mode)
433 (setq current-gud-buffer (current-buffer))))) 510 (setq gud-comint-buffer (current-buffer)))))
434 511
435(defun gud-filter (proc string) 512;; These functions are responsible for inserting output from your debugger
436 ;; This function is responsible for inserting output from your debugger 513;; into the buffer. The hard work is done by the method that is
437 ;; into the buffer. The hard work is done by the method that is 514;; the value of gud-marker-filter.
438 ;; the value of gud-marker-filter.
439 (let ((inhibit-quit t))
440 (gud-filter-insert proc (gud-marker-filter proc string))
441 ;; If we've got queued commands and we see a prompt, pop one and send it.
442 ;; In theory we should check that a prompt has been issued before sending
443 ;; queued commands. In practice, command responses from the first through
444 ;; penultimate elements of a command sequence are short enough that we
445 ;; don't really have to bother.
446 (if gud-command-queue
447 (progn
448 (gud-call (car gud-command-queue))
449 (setq gud-command-queue (cdr gud-command-queue))
450 )
451 )))
452 515
453(defun gud-filter-insert (proc string) 516(defun gud-filter (proc string)
454 ;; Here's where the actual buffer insertion is done 517 ;; Here's where the actual buffer insertion is done
455 (save-excursion 518 (let ((inhibit-quit t))
456 (set-buffer (process-buffer proc)) 519 (save-excursion
457 (let ((moving (= (point) (process-mark proc))) 520 (set-buffer (process-buffer proc))
458 (output-after-point (< (point) (process-mark proc)))) 521 (let ((moving (= (point) (process-mark proc)))
459 (save-excursion 522 (output-after-point (< (point) (process-mark proc))))
460 (goto-char (process-mark proc)) 523 (save-excursion
461 ;; If we have been so requested, delete the debugger prompt. 524 (goto-char (process-mark proc))
462 (if (marker-buffer gud-delete-prompt-marker) 525 ;; If we have been so requested, delete the debugger prompt.
463 (progn 526 (if (marker-buffer gud-delete-prompt-marker)
464 (delete-region (point) gud-delete-prompt-marker) 527 (progn
465 (set-marker gud-delete-prompt-marker nil))) 528 (delete-region (point) gud-delete-prompt-marker)
466 (insert-before-markers string) 529 (set-marker gud-delete-prompt-marker nil)))
467 ;; Check for a filename-and-line number. 530 (insert-before-markers (gud-marker-filter string))
468 ;; Don't display the specified file 531 ;; Check for a filename-and-line number.
469 ;; unless (1) point is at or after the position where output appears 532 ;; Don't display the specified file
470 ;; and (2) this buffer is on the screen. 533 ;; unless (1) point is at or after the position where output appears
471 (if (and gud-last-frame 534 ;; and (2) this buffer is on the screen.
472 (not output-after-point) 535 (if (and gud-last-frame
473 (get-buffer-window (current-buffer))) 536 (not output-after-point)
474 (gud-display-frame))) 537 (get-buffer-window (current-buffer)))
475 (if moving (goto-char (process-mark proc)))))) 538 (gud-display-frame)))
539 (if moving (goto-char (process-mark proc)))))))
476 540
477(defun gud-sentinel (proc msg) 541(defun gud-sentinel (proc msg)
478 (cond ((null (buffer-name (process-buffer proc))) 542 (cond ((null (buffer-name (process-buffer proc)))
479 ;; buffer killed 543 ;; buffer killed
480 ;; Stop displaying an arrow in a source file. 544 ;; Stop displaying an arrow in a source file.
481 (setq overlay-arrow-position nil) 545 (setq overlay-arrow-position nil)
546 (setq gud-minor-mode nil)
482 (set-process-buffer proc nil)) 547 (set-process-buffer proc nil))
483 ((memq (process-status proc) '(signal exit)) 548 ((memq (process-status proc) '(signal exit))
484 ;; Stop displaying an arrow in a source file. 549 ;; Stop displaying an arrow in a source file.
550 (setq gud-minor-mode nil)
485 (setq overlay-arrow-position nil) 551 (setq overlay-arrow-position nil)
486 ;; Fix the mode line. 552 ;; Fix the mode line.
487 (setq mode-line-process 553 (setq mode-line-process
@@ -509,19 +575,12 @@ comint mode, which see."
509 ;; if obuf is the gud buffer. 575 ;; if obuf is the gud buffer.
510 (set-buffer obuf)))))) 576 (set-buffer obuf))))))
511 577
512
513(defun gud-refresh (&optional arg)
514 "Fix up a possibly garbled display, and redraw the arrow."
515 (interactive "P")
516 (recenter arg)
517 (gud-display-frame))
518
519(defun gud-display-frame () 578(defun gud-display-frame ()
520 "Find and obey the last filename-and-line marker from the debugger. 579 "Find and obey the last filename-and-line marker from the debugger.
521Obeying it means displaying in another window the specified file and line." 580Obeying it means displaying in another window the specified file and line."
522 (interactive) 581 (interactive)
523 (if gud-last-frame 582 (if gud-last-frame
524 (progn 583 (progn
525 (gud-set-buffer) 584 (gud-set-buffer)
526 (gud-display-line (car gud-last-frame) (cdr gud-last-frame)) 585 (gud-display-line (car gud-last-frame) (cdr gud-last-frame))
527 (setq gud-last-frame nil)))) 586 (setq gud-last-frame nil))))
@@ -529,13 +588,18 @@ Obeying it means displaying in another window the specified file and line."
529;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen 588;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen
530;; and that its line LINE is visible. 589;; and that its line LINE is visible.
531;; Put the overlay-arrow on the line LINE in that buffer. 590;; Put the overlay-arrow on the line LINE in that buffer.
591;; Most of the trickiness in here comes from wanting to preserve the current
592;; region-restriction if that's possible. We use an explicit display-buffer
593;; to get around the fact that this is called inside a save-excursion.
532 594
533(defun gud-display-line (true-file line) 595(defun gud-display-line (true-file line)
534 (let* ((buffer (gud-visit-file true-file)) 596 (let* ((buffer (gud-find-file true-file))
535 (window (display-buffer buffer t)) 597 (window (display-buffer buffer))
536 (pos)) 598 (pos))
537 (save-excursion 599 (save-excursion
538 (set-buffer buffer) 600 (set-buffer buffer)
601 (make-local-variable 'gud-minor-mode)
602 (setq gud-minor-mode t)
539 (save-restriction 603 (save-restriction
540 (widen) 604 (widen)
541 (goto-line line) 605 (goto-line line)
@@ -548,62 +612,60 @@ Obeying it means displaying in another window the specified file and line."
548 (widen) 612 (widen)
549 (goto-char pos)))) 613 (goto-char pos))))
550 (set-window-point window overlay-arrow-position))) 614 (set-window-point window overlay-arrow-position)))
551
552(defun gud-call (command &rest args)
553 "Invoke the debugger COMMAND displaying source in other window."
554 (interactive)
555 (gud-set-buffer)
556 (let ((command (concat (apply 'format command args) "\n"))
557 (proc (get-buffer-process current-gud-buffer)))
558
559 ;; Arrange for the current prompt to get deleted.
560 (save-excursion
561 (set-buffer current-gud-buffer)
562 (goto-char (process-mark proc))
563 (beginning-of-line)
564 (if (looking-at comint-prompt-regexp)
565 (set-marker gud-delete-prompt-marker (point))))
566 615
567 (goto-char (point-max)) 616;;; The gud-call function must do the right thing whether its invoking
568 (process-send-string proc command))) 617;;; keystroke is from the GUD buffer itself (via major-mode binding)
618;;; or a C buffer in GUD minor mode. In the former case, we want to
619;;; supply data from gud-last-frame. Here's how we do it:
569 620
570(defun gud-queue-send (&rest cmdlist) 621(defun gud-format-command (str arg)
571 ;; Send the first command, queue the rest for send after successive 622 (let ((minor (not (eq (current-buffer) gud-comint-buffer))))
572 ;; send on subsequent prompts 623 (if (string-match "\\(.*\\)%f\\(.*\\)" str)
573 (interactive) 624 (progn
574 (gud-call (car cmdlist)) 625 (setq str (concat
575 (setq gud-command-queue (append gud-command-queue (cdr cmdlist)))) 626 (substring str (match-beginning 1) (match-end 1))
576 627 (if minor
577(defun gud-apply-from-source (func &rest args) 628 (buffer-file-name)
578 ;; Apply a method from the gud buffer environment, passing it file 629 (car gud-last-frame))
579 ;; and line, then ARGS. This is intended to be used for gud 630 (substring str (match-beginning 2) (match-end 2))))))
580 ;; commands called from a source file. 631 (if (string-match "\\(.*\\)%l\\(.*\\)" str)
581 (if (not buffer-file-name) 632 (progn
582 (error "There is no file associated with this buffer")) 633 (setq str (concat
583 (let ((file (file-name-nondirectory buffer-file-name)) 634 (substring str (match-beginning 1) (match-end 1))
584 (line (save-restriction (widen) (1+ (count-lines 1 (point)))))) 635 (if minor
585 (save-excursion 636 (save-excursion
586 (gud-set-buffer) 637 (beginning-of-line)
587 (apply func 638 (save-restriction (widen)
588 (get-buffer-process current-gud-buffer) 639 (1+ (count-lines 1 (point)))))
589 file 640 (cdr gud-last-frame))
590 line 641 (substring str (match-beginning 2) (match-end 2))))))
591 args) 642 (if (string-match "\\(.*\\)%e\\(.*\\)" str)
592 ))) 643 (progn
593 644 (setq str (concat
594(defun gud-break (arg) 645 (substring str (match-beginning 1) (match-end 1))
595 "Set breakpoint at this source line. 646 (find-c-expr)
596With prefix argument, set a temporary breakpoint, if the debugger in 647 (substring str (match-beginning 2) (match-end 2))))))
597use supports such things. (A temporary breakpoint is one which will 648 (if (string-match "\\(.*\\)%a\\(.*\\)" str)
598be deleted when it is reached.)" 649 (progn
599 (interactive "P") 650 (setq str (concat
600 (gud-apply-from-source 'gud-set-break arg)) 651 (substring str (match-beginning 1) (match-end 1))
652 (gud-read-address)
653 (substring str (match-beginning 2) (match-end 2))))))
654 (if (string-match "\\(.*\\)%p\\(.*\\)" str)
655 (progn
656 (setq str (concat
657 (substring str (match-beginning 1) (match-end 1))
658 (if arg (int-to-string arg) "")
659 (substring str (match-beginning 2) (match-end 2))))))
660 )
661 str
662 )
601 663
602(defun gud-read-address () 664(defun gud-read-address ()
603 "Return a string containing the core-address found in the buffer at point." 665 "Return a string containing the core-address found in the buffer at point."
604 (save-excursion 666 (save-excursion
605 (let ((pt (point)) found begin) 667 (let ((pt (point)) found begin)
606 (setq found (if (search-backward "0x" (- pt 7) t)(point))) 668 (setq found (if (search-backward "0x" (- pt 7) t) (point)))
607 (cond 669 (cond
608 (found (forward-char 2) 670 (found (forward-char 2)
609 (buffer-substring found 671 (buffer-substring found
@@ -618,26 +680,183 @@ be deleted when it is reached.)"
618 (forward-char -1) 680 (forward-char -1)
619 (buffer-substring begin (point))))))) 681 (buffer-substring begin (point)))))))
620 682
683(defun gud-call (fmt &optional arg)
684 (let ((msg (gud-format-command fmt arg)))
685 (message "Command: %s" msg)
686 (sit-for 0)
687 (gud-basic-call msg)))
621 688
622(defun send-gud-command (arg) 689(defun gud-basic-call (command)
623 "This command reads the number where the cursor is positioned. A numeric arg 690 "Invoke the debugger COMMAND displaying source in other window."
624selects the ARG'th member COMMAND of the list gud-commands. If COMMAND is a 691 (interactive)
625string, (format COMMAND ADDR) is inserted at the end of the debugger buffer, 692 (gud-set-buffer)
626otherwise (funcall COMMAND ADDR) is inserted. 693 (let ((command (concat command "\n"))
627 For example, \"p (rtx)%s->fld[0].rtint\" is a possible string to be a 694 (proc (get-buffer-process gud-comint-buffer)))
628member of gud-commands." 695
696 ;; Arrange for the current prompt to get deleted.
697 (save-excursion
698 (set-buffer gud-comint-buffer)
699 (goto-char (process-mark proc))
700 (beginning-of-line)
701 (if (looking-at comint-prompt-regexp)
702 (set-marker gud-delete-prompt-marker (point))))
703 (process-send-string proc command)))
704
705(defun gud-refresh (&optional arg)
706 "Fix up a possibly garbled display, and redraw the arrow."
629 (interactive "P") 707 (interactive "P")
630 (let (comm addr) 708 (recenter arg)
631 (if arg (setq comm (nth arg gud-commands))) 709 (gud-display-frame))
632 (setq addr (gud-read-address)) 710
633 (if (eq (current-buffer) current-gud-buffer) 711;;; Code for parsing expressions out of C code. The single entry point is
634 (set-mark (point))) 712;;; find-c-expr, which tries to return an lvalue expression from around point.
635 (cond (comm 713;;;
636 (setq comm 714;;; The rest of this file is a hacked version of gdbsrc.el by
637 (if (stringp comm) (format comm addr) (funcall comm addr)))) 715;;; Debby Ayers <ayers@asc.slb.com>,
638 (t (setq comm addr))) 716;;; Rich Schaefer <schaefer@asc.slb.com> Schlumberger, Austin, Tx.
639 (switch-to-buffer current-gud-buffer) 717;;; ??? We're waiting on papers from these people
640 (goto-char (point-max)) 718
641 (insert-string comm))) 719(defun find-c-expr ()
720 "Returns the C expr that surrounds point."
721 (interactive)
722 (save-excursion
723 (let ((p) (expr) (test-expr))
724 (setq p (point))
725 (setq expr (expr-cur))
726 (setq test-expr (expr-prev))
727 (while (expr-compound test-expr expr)
728 (setq expr (cons (car test-expr) (cdr expr)))
729 (goto-char (car expr))
730 (setq test-expr (expr-prev))
731 )
732 (goto-char p)
733 (setq test-expr (expr-next))
734 (while (expr-compound expr test-expr)
735 (setq expr (cons (car expr) (cdr test-expr)))
736 (setq test-expr (expr-next))
737 )
738 (buffer-substring (car expr) (cdr expr))
739 )
740 )
741 )
742
743(defun expr-cur ()
744 "Returns the expr that point is in; point is set to beginning of expr.
745The expr is represented as a cons cell, where the car specifies the point in
746the current buffer that marks the beginning of the expr and the cdr specifies
747the character after the end of the expr"
748 (let ((p (point)) (begin) (end))
749 (back-expr)
750 (setq begin (point))
751 (forw-expr)
752 (setq end (point))
753 (if (>= p end)
754 (progn
755 (setq begin p)
756 (goto-char p)
757 (forw-expr)
758 (setq end (point))
759 )
760 )
761 (goto-char begin)
762 (cons begin end)
763 )
764 )
765
766(defun back-expr ()
767 "Version of backward-sexp that catches errors"
768 (condition-case nil
769 (backward-sexp)
770 (error t)))
771
772(defun forw-expr ()
773 "Version of forward-sexp that catches errors"
774 (condition-case nil
775 (forward-sexp)
776 (error t)))
777
778(defun expr-prev ()
779 "Returns the previous expr, point is set to beginning of that expr.
780The expr is represented as a cons cell, where the car specifies the point in
781the current buffer that marks the beginning of the expr and the cdr specifies
782the character after the end of the expr"
783 (let ((begin) (end))
784 (back-expr)
785 (setq begin (point))
786 (forw-expr)
787 (setq end (point))
788 (goto-char begin)
789 (cons begin end)))
790
791(defun expr-next ()
792 "Returns the following expr, point is set to beginning of that expr.
793The expr is represented as a cons cell, where the car specifies the point in
794the current buffer that marks the beginning of the expr and the cdr specifies
795the character after the end of the expr"
796 (let ((begin) (end))
797 (forw-expr)
798 (forw-expr)
799 (setq end (point))
800 (back-expr)
801 (setq begin (point))
802 (cons begin end)
803 )
804 )
805
806(defun expr-compound-sep (span-start span-end)
807 "Returns '.' for '->' & '.', returns ' ' for white space,
808returns '?' for other puctuation."
809 (let ((result ? )
810 (syntax))
811 (while (< span-start span-end)
812 (setq syntax (char-syntax (char-after span-start)))
813 (cond
814 ((= syntax ? ) t)
815 ((= syntax ?.) (setq syntax (char-after span-start))
816 (cond
817 ((= syntax ?.) (setq result ?.))
818 ((and (= syntax ?-) (= (char-after (+ span-start 1)) ?>))
819 (setq result ?.)
820 (setq span-start (+ span-start 1)))
821 (t (setq span-start span-end)
822 (setq result ??)))))
823 (setq span-start (+ span-start 1)))
824 result
825 )
826 )
827
828(defun expr-compound (first second)
829 "Returns non-nil if the concatenation of two exprs results in a single C
830token. The two exprs are represented as a cons cells, where the car
831specifies the point in the current buffer that marks the beginning of the
832expr and the cdr specifies the character after the end of the expr
833Link exprs of the form:
834 Expr -> Expr
835 Expr . Expr
836 Expr (Expr)
837 Expr [Expr]
838 (Expr) Expr
839 [Expr] Expr"
840 (let ((span-start (cdr first))
841 (span-end (car second))
842 (syntax))
843 (setq syntax (expr-compound-sep span-start span-end))
844 (cond
845 ((= (car first) (car second)) nil)
846 ((= (cdr first) (cdr second)) nil)
847 ((= syntax ?.) t)
848 ((= syntax ? )
849 (setq span-start (char-after (- span-start 1)))
850 (setq span-end (char-after span-end))
851 (cond
852 ((= span-start ?) ) t )
853 ((= span-start ?] ) t )
854 ((= span-end ?( ) t )
855 ((= span-end ?[ ) t )
856 (t nil))
857 )
858 (t nil))
859 )
860 )
642 861
643;;; gud.el ends here 862;;; gud.el ends here