デフォルトではパース処理はカレントバッファーのポイントを単に移動して、最終的にはパースが成功すればt
、失敗すればnil
をリターンします。パースしたテキスト内の特定のポイントで任意のElispを実行できるパースアクション(parsing
actions)を定義することも可能です。これらのアクションはオプションで、パーススタック(parsing
stack)と呼ばれるパースプロセスによってリターンされる値リストに影響を与えることができます。これらのアクションはパースプロセスが最終的に成功した場合のみ実行(および値のリターン)されます。失敗した場合にはアクションのコードは何も実行されません。
アクションはルール定義のどこでも追加できます。アクションは先頭にバッククォートを記述することでパース式とは区別されます。バッククォートの後には2つのハイフン(‘--’)をどこかに含んだカッコの括りが続きます。ハイフン左側のシンボルにはスタックからポップされた値にバインドされます(幾分ラムダ式の引数リストに似ている)。ハイフン右側のコードが生成した値はスタックへとプッシュされます(ラムダのリターン値と似ている)。たとえば前述したグラマーはパースした数値を実際の整数としてリターンするアクションに拡張できます:
(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))))
上記1つ目のアクションはポイントの初期値をスタックにプッシュしています。アクションの間に記述されたPEXによって、ポイントが次の単語の上に移動します。2つ目のアクションにより、前の値をスタックからポップします(その値は変数start
にバインドされてから、バッファーからの部分文字列抽出に使用されて、抽出された文字列はスタックにプッシュされる)。これははよくあるパターンなので上述の処理、および他の一般的なシナリオを正確こなす略記関数をPEGが提供しています。
(substring e)
PEXのeをマッチして、マッチした文字列をスタックにプッシュする。
(region e)
eをマッチして、マッチしたリージョンの開始と終了をスタックにプッシュする。
(replace e replacement)
eをマッチして、マッチしたリージョンを文字列replacementで置き換える。
(list e)
eをマッチして、e (とその部分式)が生成した値をリストに収集、そのリストをスタックにプッシュする。スタック値は通常はフラットなリストとしてリターンされる(この方法により複数の値を一緒に“グループ化”される)。