我在Windows上使用GNU Emacs 23.3。我在一个非常大的代码库中工作,我生成一个TAGS文件(使用Emacs提供的etags二进制文件)。 TAGS文件非常大(通常徘徊在100MB左右)。我很少需要使用find-tag
以外的任何功能,但有时我希望我可以完成TAGS表。
调用complete-tag
会导致Emacs自动生成完成表。这个过程需要相当长的时间,但我的问题不在于花费的时间,而是在最后(大约100%完成)的事实,我得到一个堆栈溢出(抱歉不可打印的字符) ):
Debugger entered--Lisp error: (error "Stack overflow in regexp matcher")
re-search-forward("^\\(\\([^]+[^-a-zA-Z0-9_+*$:]+\\)?\\([-a-zA-Z0-9_+*$?:]+\\)[^-a-zA-Z0-9_+*$?:]*\\)\\(\\([^\n]+\\)\\)?\\([0-9]+\\)?,\\([0-9]+\\)?\n" nil t)
etags-tags-completion-table()
byte-code(...)
tags-completion-table()
有没有其他人遇到这个?知道一种解决方法吗?
编辑:开启debug-on-error
编辑:删除了堆栈,因为我现在知道失败的条目是什么样的:
^L
c:\path\to\some\header.h,0
^L
c:\path\to\some\otherheader.h,0
我的代码文件包含此格式的相当多的条目。查看所涉及的标题,很明显etags无法正确解析它们。这很好,但我很惊讶tags-completion-table
在其正则表达式中没有考虑这种格式。作为参考,这是一个真正的条目:
^L
c:\path\to\some\validheader.h,115
class CSomeClass ^?12,345
bool SomeMethod(^?CSomeClass::SomeMethod^A67,890
答案 0 :(得分:3)
有问题的正则表达式用于匹配TAGS
文件中的标记条目。我想如果文件格式不正确(例如使用非本地行结尾),或者条目真的非常非常大,则会发生错误。 (条目通常是一行或两行,这对于正则表达式匹配器来说应该不是问题。)
跟踪问题的一种方法是转到TAGS缓冲区,并在发生错误后查看点(光标)的位置。一旦你知道它是哪个功能,并且你可以没有它的标签,你可以简单地避免为它生成TAGS条目。
如果问题是由于过于复杂的输入,我建议您将错误报告发送给Emacs团队。
答案 1 :(得分:1)
如果您加载标签表(使用Emacs打开TAGS表,然后bury-buffer
),请尝试M-x dabbrev-expand
(绑定到M-/
)。如果当前前缀非常常见,您可能最终会在达到所需的完成之前运行许多可能的完成。
我不使用Windows,但在我使用的Mac和Linux机器上,我没有遇到过这个问题。
答案 2 :(得分:0)
这看起来像是Emacs中的一个错误,请参阅:
我已将建议的修补程序应用于etags-tags-completion-table
(为方便起见,请在下面完整复制)并遇到错误情况。
我在极长的代码行中触发错误(46,000个字符!)。我假设某人以编程方式生成了该行并将其粘贴到源代码中。一个解决方法可能是简单地在ctag建筑物或装载阶段过滤这些线条,只是删除" long"线条,无论可能意味着什么。可能500个字符足够长!
我还可以考虑在ctags中为我的正则表达式添加最大大小,但这不是一般解决方案,因为许多ctags模式没有这样的限制。
(defun etags-tags-completion-table () ; Doc string?
(let ((table (make-vector 511 0))
(progress-reporter
(make-progress-reporter
(format "Making tags completion table for %s..." buffer-file-name)
(point-min) (point-max))))
(save-excursion
(goto-char (point-min))
;; This monster regexp matches an etags tag line.
;; \1 is the string to match;
;; \2 is not interesting;
;; \3 is the guessed tag name; XXX guess should be better eg DEFUN
;; \4 is not interesting;
;; \5 is the explicitly-specified tag name.
;; \6 is the line to start searching at;
;; \7 is the char to start searching at.
(condition-case err
(while (re-search-forward
"^\\(\\([^\177]+[^-a-zA-Z0-9_+*$:\177]+\\)?\
\\([-a-zA-Z0-9_+*$?:]+\\)[^-a-zA-Z0-9_+*$?:\177]*\\)\177\
\\(\\([^\n\001]+\\)\001\\)?\\([0-9]+\\)?,\\([0-9]+\\)?\n"
nil t)
(intern (prog1 (if (match-beginning 5)
;; There is an explicit tag name.
(buffer-substring (match-beginning 5) (match-end 5))
;; No explicit tag name. Best guess.
(buffer-substring (match-beginning 3) (match-end 3)))
(progress-reporter-update progress-reporter (point)))
table))
(error
(message "error happened near %d" (point))
(error (error-message-string err)))))
table))