Как исправить "переполнение стека в регулярных выражениях" в emacs
Я большой поклонник Emacs и часто его использую, особенно при программировании и отладке (с использованием gud) (C/C++).
Недавно мне пришлось отлаживать программу (довольно простую, но рассчитанную на большом количестве данных (Теория графов)), но у меня была довольно раздражающая проблема. Во время выполнения пошаговой программы я получаю следующую ошибку:
error in process filter: Stack overflow in regexp matcher
Я провел некоторое исследование, чтобы выяснить, что это было, и обнаружил этот пост: отладка в emacs (с помощью gud) часто приводит к ошибке переполнения стека.
Итак, насколько я понимаю, существует проблема с сопоставителем регулярных выражений и с тем, что некоторые вещи в моей программе просто слишком длинные? (У меня есть необычно длинное имя функции с большим количеством параметров, и я также использую необычно большой контейнер.)
Я бы очень хотел это исправить, но я ничего не знаю об отладке Emacs Lisp, есть кто-нибудь, кто мне поможет?
Вот вывод, полученный от внутреннего отладчика Emacs: http://pastebin.com/5CKe74e6
Я также должен отметить, что я использую персонализированную версию Emacs Prelude.
2 ответа
Основная проблема заключается в том, что регулярное выражение (regexp) содержит слишком много альтернатив, и при применении к (обычно длинному) тексту оно не может соответствовать тому, что пыталось найти.
В вашем случае это регулярное выражение:
"\\([[:alnum:]-_]+\\)=\\({\\|\\[\\|\"\"\\|\"\\(?:[^\\\"]\\|\\\\.\\)*\"\\)"
Который используется функцией gdb-jsonify-buffer
,
Похоже, это регулярное выражение пытается сопоставить назначения. По сути, это соответствует переменной слева от =
и (часть) выражение справа. Похоже, регулярному выражению соответствует строка, содержащая экранированные кавычки - это всегда предупреждающий знак, так как Emacs предоставляет гораздо лучшие методы для разбора строк.
Проблема может возникать из-за того, что это регулярное выражение неверно (так что оно соответствует намного больше, чем ваша строка), что у вас неправильно сформированная строка или что ваша программа просто содержит действительно большую строку.
Я бы посоветовал вам отправить отчет об ошибке сопровождающему этого пакета. Убедитесь, что вы включили текст, вызвавший ошибку.
Кроме того, вы можете попытаться исправить это самостоятельно. Я бы предложил заменить сложное регулярное выражение на более простое регулярное выражение, которое находит начало строки. Затем вы можете использовать, например, (forward-sexp)
найти конец строки.
У меня также была эта проблема, поэтому я воспользовался предложением Lindydancer о преобразовании регулярного выражения в строковом литерале для использования (forward-sexp), и оно работало нормально для меня.
Я разместил патч:
http://lists.gnu.org/archive/html/bug-gnu-emacs/2017-12/msg00968.html
так что, надеюсь, в какой-то момент он будет объединен. А пока вы можете использовать это для gdb-jsonify-buffer:
(defun gdb-jsonify-buffer (&optional fix-key fix-list)
"Prepare GDB/MI output in current buffer for parsing with `json-read'.
Field names are wrapped in double quotes and equal signs are
replaced with semicolons.
If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from
partial output. This is used to get rid of useless keys in lists
in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
-break-info are examples of MI commands which issue such
responses.
If FIX-LIST is non-nil, \"FIX-LIST={..}\" is replaced with
\"FIX-LIST=[..]\" prior to parsing. This is used to fix broken
-break-info output when it contains breakpoint script field
incompatible with GDB/MI output syntax.
If `default-directory' is remote, full file names are adapted accordingly."
(save-excursion
(let ((remote (file-remote-p default-directory)))
(when remote
(goto-char (point-min))
(while (re-search-forward "[\\[,]fullname=\"\\(.+\\)\"" nil t)
(replace-match (concat remote "\\1") nil nil nil 1))))
(goto-char (point-min))
(when fix-key
(save-excursion
(while (re-search-forward (concat "[\\[,]\\(" fix-key "=\\)") nil t)
(replace-match "" nil nil nil 1))))
(when fix-list
(save-excursion
;; Find positions of braces which enclose broken list
(while (re-search-forward (concat fix-list "={\"") nil t)
(let ((p1 (goto-char (- (point) 2)))
(p2 (progn (forward-sexp)
(1- (point)))))
;; Replace braces with brackets
(save-excursion
(goto-char p1)
(delete-char 1)
(insert "[")
(goto-char p2)
(delete-char 1)
(insert "]"))))))
(goto-char (point-min))
(insert "{")
(let ((re (concat "\\([[:alnum:]-_]+\\)=")))
(while (re-search-forward re nil t)
(replace-match "\"\\1\":" nil nil)
(if (eq (char-after) ?\") (forward-sexp) (forward-char))))
(goto-char (point-max))
(insert "}")))