在emacs中生成标签完成表时堆栈溢出

时间:2011-03-27 18:35:46

标签: emacs tags

我在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

3 个答案:

答案 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))