imenu与函数指针

imenu可以定位C/C++文件里的函数,配合anything使用,非常方便。可是我却发现,它无法定位带有函数指针作为参数的函数,如gcc/genattrtab.c里面的

static rtx
substitute_address (rtx exp, rtx (*no_address_fn) (rtx),
                    rtx (*address_fn) (rtx))

查看imenu的代码后发现,原来imenu是一个framework,具体的定位功能,是由相应的major mode实现的,我发现的问题,其实是cc-mode的实现有缺陷。在报了bug几天后,CC mode maintainer解决了这个问题。如果暂时没法(或不愿意)升级到最新的开发版,可以在自己的.emacs文件里添加如下配置,对于已经打开的文件,需要revert-buffer才能奏效。两个setq语句是从lisp/progmodes/cc-menus.el里摘录出来,如果下面的代码看不清楚,可以从源文件里直接复制。

(eval-after-load 'cc-mode
  '(progn
     (setq cc-imenu-c++-generic-expression
	   `(
	     ;; Try to match ::operator definitions first. Otherwise `X::operator new ()'
	     ;; will be incorrectly recognised as function `new ()' because the regexps
	     ;; work by backtracking from the end of the definition.
	     (nil
	      ,(concat
		"^\\< .*"
		"[^" c-alnum "_:<>~]"                  ; match any non-identifier char
					; (note: this can be `\n')
		"\\("
		"\\([" c-alnum "_:<>~]*::\\)?"      ; match an operator
		"operator\\>[ \t]*"
		"\\(()\\|[^(]*\\)"                  ; special case for `()' operator
		"\\)"

		"[ \t]*([^)]*)[ \t]*[^ \t;]"           ; followed by ws, arg list,
					; require something other than
					; a `;' after the (...) to
					; avoid prototypes.  Can't
					; catch cases with () inside
					; the parentheses surrounding
					; the parameters.  e.g.:
					; `int foo(int a=bar()) {...}'
		) 1)
	     ;; Special case to match a line like `main() {}'
	     ;; e.g. no return type, not even on the previous line.
	     (nil
	      ,(concat
		"^"
		"\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name
		"[ \t]*("			      ; see above, BUT
		"[ \t]*\\([^ \t(*][^)]*\\)?)"          ; the arg list must not start
		"[ \t]*[^ \t;(]"                       ; with an asterisk or parentheses
		) 1)
	     ;; General function name regexp
	     (nil
	      ,(concat
		"^\\< "                                 ; line MUST start with word char
		;; \n added to prevent overflow in regexp matcher.
		;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-02/msg00021.html
		"[^()\n]*"                             ; no parentheses before
		"[^" c-alnum "_:<>~]"                  ; match any non-identifier char
		"\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name
		"\\([ \t\n]\\|\\\\\n\\)*("	      ; see above, BUT the arg list
		"\\([ \t\n]\\|\\\\\n\\)*"            ; must not start
		"\\([^ \t\n(*]"                              ; with an asterisk or parentheses
		"[^()]*\\(([^()]*)[^()]*\\)*"        ; Maybe function pointer arguments
		"\\)?)"
		"\\([ \t\n]\\|\\\\\n\\)*[^ \t\n;(]"
		) 1)
	     ;; Special case for definitions using phony prototype macros like:
	     ;; `int main _PROTO( (int argc,char *argv[]) )'.
	     ;; This case is only included if cc-imenu-c-prototype-macro-regexp is set.
	     ;; Only supported in c-code, so no `:<>~' chars in function name!
	     ,@(if cc-imenu-c-prototype-macro-regexp
		   `((nil
		      ,(concat
			"^\\< .*"                   ; line MUST start with word char
			"[^" c-alnum "_]"          ; match any non-identifier char
			"\\([" c-alpha "_][" c-alnum "_]*\\)" ; match function name
			"[ \t]*"                   ; whitespace before macro name
			cc-imenu-c-prototype-macro-regexp
			"[ \t]*("                  ; ws followed by first paren.
			"[ \t]*([^)]*)[ \t]*)[ \t]*[^ \t;]" ; see above
			) 1)))
	     ;; Class definitions
	     ("Class"
	      ,(concat
		"^"                                  ; beginning of line is required
		"\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a `template < ...>'
		"\\(class\\|struct\\)[ \t]+"
		"\\("                                ; the string we want to get
		"[" c-alnum "_]+"                    ; class name
		"\\(< [^>]+>\\)?"                     ; possibly explicitly specialized
		"\\)"
		"\\([ \t\n]\\|\\\\\n\\)*[:{]"
		) 3)))
     (setq cc-imenu-c-generic-expression
	   cc-imenu-c++-generic-expression)))

4 thoughts on “imenu与函数指针

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据