Грамматики разбора выражений
Emacs Lisp предоставляет несколько инструментов для разбора и сопоставления текста: от регулярных выражений (см. Регулярные выражения) до полноценных парсеров грамматик слева направо (так называемых LL) (см. Разработка парсеров Bovine). Грамматики разбора выражений (PEG) — ещё один способ разбора текста, обеспечивающий большую структурированность и возможность композиции по сравнению с регулярными выражениями, но менее сложный, чем контекстно-свободные грамматики.
Грамматика разбора выражений (PEG) описывает формальный язык как набор правил распознавания строк этого языка. В Emacs парсер PEG определяется списком именованных правил, каждое из которых сопоставляет текстовые шаблоны и/или содержит ссылки на другие правила. Разбор запускается функцией peg-run или макросом peg-parse (см. ниже) и разбирает текст после точки в текущем буфере, используя заданный набор правил.
Каждое правило в PEG называется выражением разбора (PEX). Его можно задать строковым литералом, диапазоном или набором символов в стиле регулярных выражений, специальной конструкцией PEG, похожей на вызов функции Emacs Lisp, ссылкой на другое правило или комбинацией этих вариантов. Грамматика представляется в виде дерева правил, в котором одно из правил обычно считается «корневым» или «входным». Например:
((number sign digit (* digit)) (sign (or "+" "-" "")) (digit [0-9]))
После определения грамматики можно использовать для разбора текста после точки в текущем буфере несколькими способами. Макрос peg-parse — самый простой из них:
- Макрос: peg-parse &rest pexs
Сопоставляет pexs с текстом в точке.
(peg-parse (number sign digit (* digit)) (sign (or "+" "-" "")) (digit [0-9]))
Этот макрос прост, но негибок: правила необходимо записывать непосредственно в исходном коде. Большую гибкость можно получить, комбинируя другие функции и макросы.
- Макрос: with-peg-rules rules &rest body
Выполняет body с активным набором rules — списком выражений PEX. Внутри BODY разбор запускается вызовом
peg-run.
- Функция: peg-run peg-matcher &optional failure-function success-function
-
Эта функция принимает один аргумент peg-matcher — результат вызова
peg(см. ниже) для именованного правила, обычно входного правила более крупной грамматики.По завершении разбора вызывается либо failure-function, либо success-function — в зависимости от того, завершился ли разбор успешно. Если задана success-function, она должна быть функцией, получающей в качестве единственного аргумента анонимную функцию, которая выполняет все действия, накопленные в стеке во время разбора. По умолчанию эта анонимная функция просто выполняется. Если разбор завершается неудачей, функция, заданная в failure-function, вызывается со списком выражений PEG, сопоставление которых не удалось во время разбора. По умолчанию этот список отбрасывается.
Аргумент peg-matcher, передаваемый в peg-run, создаётся вызовом peg:
- Макрос: peg &rest pexs
Преобразует pexs в единый peg-matcher, который можно передать в
peg-run.
Приведённый выше пример peg-parse разворачивается в набор вызовов этих функций и в полном виде может быть записан так:
(with-peg-rules
((number sign digit (* digit))
(sign (or "+" "-" ""))
(digit [0-9]))
(peg-run (peg number)))
Такой подход позволяет явно управлять «входной точкой» разбора и комбинировать правила из разных источников.
Отдельные правила также можно определять с помощью синтаксиса, более похожего на defun, используя макрос define-peg-rule:
- Макрос: define-peg-rule name args &rest pexs
Определяет name как правило PEG, принимающее args и сопоставляющее pexs с текстом в точке.
Например:
(define-peg-rule digit () [0-9])
Аргументы можно передавать правилам с помощью правила PEG funcall (см. Определения PEX).
Другой вариант — определить именованный набор правил с помощью define-peg-ruleset:
- Макрос: define-peg-ruleset name &rest rules
Определяет name как идентификатор для rules.
(define-peg-ruleset number-grammar ;; `digit' here references the definition above. (number () sign digit (* digit)) (sign () (or "+" "-" "")))
Правила и наборы правил, определённые таким образом, можно указывать по имени в последующих вызовах peg-run или with-peg-rules:
(with-peg-rules number-grammar (peg-run (peg number)))
По умолчанию вызовы peg-run или peg-parse не создают вывод: разбор лишь перемещает точку. Чтобы вернуть разобранные строки или выполнить с ними другие действия, правила могут содержать действия; см. Действия при разборе.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-Expression-Grammars.html