Переполнение стека при генерации таблицы завершения тегов в emacs - PullRequest
7 голосов
/ 27 марта 2011

Я использую GNU Emacs 23.3 в Windows. Я работаю в очень большой кодовой базе, для которой генерирую файл TAGS (используя бинарный файл etags, поставляемый с Emacs). Файл TAGS довольно большой (обычно занимает около 100 МБ). Мне редко нужно использовать какую-либо функциональность, кроме 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 ]

3 голосов
/ 30 марта 2011

Соответствующее регулярное выражение используется для сопоставления записи тега внутри файла TAGS.Я предполагаю, что ошибка может произойти, если файл неправильно отформатирован (например, с использованием неродных окончаний строк), или если запись просто очень, очень большая.(Запись обычно представляет собой строку или две, что не должно быть проблемой для сопоставителя регулярных выражений.)

Один из способов отследить проблему - перейти в буфер TAGS и посмотреть, где находится точка (курсор).после того, как произошла ошибка.Как только вы узнаете, какая это функция, и можете обойтись без тегов, вы можете просто не создавать для нее записи TAGS.

Если проблема вызвана слишком сложной записью, я бы посоветовал вам отправитьсообщение об ошибке команде Emacs.

1 голос
/ 29 марта 2011

Если вы загружаете таблицу тегов (откройте таблицу TAGS с помощью Emacs, затем bury-buffer), попробуйте M-x dabbrev-expand (привязано к M-/).Если существующий префикс является очень распространенным, вы можете выполнить множество возможных дополнений, прежде чем достигнете желаемого.

Я не использую Windows, но на компьютерах Mac и Linux, которые я использую, я не сталкивалсяэтот вопрос.

0 голосов
/ 14 января 2016

Это похоже на ошибку в Emacs, см .:

Я применилпредложил патч к etags-tags-completion-table (для удобства скопирован ниже) и уловил ошибку.

Я вызываю ошибку в очень длинной строке кода (46 000 символов!).Я предполагаю, что кто-то программно сгенерировал строку и вставил ее в источник.Обходным путем может быть простая фильтрация таких строк на этапе построения или загрузки ctag, просто что-то, что удаляет «длинные» строки, что бы это ни значило.Вероятно, 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)) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...