Spec-Zone.ru › Elisp

Действия при разборе

По умолчанию процесс разбора просто перемещает точку в текущем буфере и в конечном итоге возвращает t, если разбор завершается успешно, и nil, если он завершается неудачей. Также можно определить действия при разборе, которые выполняют произвольный код Elisp в определённых точках разбираемого текста. Эти действия могут дополнительно изменять так называемый стек разбора — список значений, возвращаемых процессом разбора. Эти действия выполняются (и возвращают значения) только в том случае, если разбор в конечном итоге завершается успешно; при неудаче код действий вообще не выполняется.

Действия можно добавлять в любое место определения правила. Они отличаются от выражений разбора начальной обратной кавычкой (‘`’), за которой следует форма в скобках, содержащая где-либо внутри пару дефисов (‘--’). Символы слева от дефисов связываются со значениями, снятыми со стека (они отчасти аналогичны списку аргументов лямбда-формы). Значения, полученные кодом справа от дефисов, помещаются в стек (аналогично возвращаемому значению лямбда-формы). Например, предыдущую грамматику можно дополнить действиями, возвращающими разобранное число как целое число:

(with-peg-rules ((number sign digit (* digit
                                       `(a b -- (+ (* a 10) b)))
                         `(sign val -- (* sign val)))
                 (sign (or (and "+" `(-- 1))
                           (and "-" `(-- -1))
                           (and ""  `(-- 1))))
                 (digit [0-9] `(-- (- (char-before) ?0))))
  (peg-run (peg number)))

Чтобы значения можно было снять со стека и вернуть, они должны находиться в стеке. Если значений в стеке недостаточно для связывания с левыми элементами действия, им будет присвоено значение nil. Действие, содержащее только правые элементы, помещает значения в стек; действие, содержащее только левые элементы, извлекает значения из стека (и отбрасывает их). В конце разбора значения стека возвращаются в виде плоского списка.

Чтобы вернуть строку, сопоставленную с PEX (вместо того чтобы просто переместить точку за её конец), грамматика может использовать такое правило:

(one-word
  `(-- (point))
  (+ [word])
  `(start -- (buffer-substring start (point))))

Первое действие выше помещает в стек исходное значение точки. Промежуточное выражение PEX перемещает точку за следующее слово. Второе действие снимает предыдущее значение со стека (связывая его с переменной start), а затем использует это значение, чтобы извлечь подстроку из буфера и поместить её в стек. Этот шаблон настолько распространён, что PEG предоставляет сокращённую функцию, выполняющую именно описанные действия, а также несколько других сокращённых функций для типичных случаев:

(substring e)

Сопоставить PEX e и поместить сопоставленную строку в стек.

(region e)

Сопоставить e и поместить в стек начальную и конечную позиции сопоставленной области.

(replace e replacement)

Сопоставить e и заменить сопоставленную область строкой replacement.

(list e)

Сопоставить e, собрать все значения, полученные выражением e (и его подвыражениями), в список и поместить этот список в стек. Обычно значения стека возвращаются в виде плоского списка; это способ «сгруппировать» значения.

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-Actions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API