По умолчанию процесс парсинга просто перемещает точку в текущем
буфере, в конечном итоге возвращая 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 (и его подвыражениями), в список и помещает этот список в стек. Значения стека обычно возвращаются в виде плоского списка; это способ "группировки" значений вместе.