examples
簡易的なS式パーサ
シンボルとリストを解釈できる簡易的なS式パーサ。パーサを構築するのに8行程度。
<?php
include_once 'PEG.php';
// パーサの構築
$space = PEG::many(PEG::char("\r\n \t"));
$symbol = PEG::join(PEG::many1(PEG::char("()\r\n\t ", true)));
$paren = PEG::third('(', $space, PEG::many(PEG::ref($atom)), ')');
$atom = PEG::memo(PEG::first(PEG::choice($paren, $symbol), $space));
$sexpr = PEG::second($space, $atom);
// コンテキストの構築
$context = PEG::context('(a (b (c ())))');
// コンテキストをパーサにかける
$result = $sexpr->parse($context);
// 結果
var_export($result);
/*
array (
0 => 'a',
1 =>
array (
0 => 'b',
1 =>
array (
0 => 'c',
1 =>
array (
),
),
),
)
*/
四則演算の数式を逆ポーランド記法に変換する
演算子や括弧で優先順位のつく四則演算の数式を解釈して逆ポーランド記法に変換するパーサ。
<?php
include_once 'PEG.php';
// フックに使う関数の定義
$fn = function($result) {
list($first, $rest) = $result;
return !$rest
? array($first)
: array_merge(array($first), call_user_func_array('array_merge', $rest));
};
$listof = function($item, $glue) use($fn) {
return PEG::hook($fn, PEG::seq($item, PEG::many($glue, $item)));
};
$torpn = function(Array $expr) use(&$torpn) {
$first = array_shift($expr);
$ret = is_array($first) ? $torpn($first) : $first ;
foreach (array_chunk($expr, 2) as $buf) {
list($op, $right) = $buf;
$ret .= (is_array($right) ? " {$torpn($right)}" : " {$right}") . " {$op}";
}
return $ret;
};
// パーサの構築
$space = PEG::many(PEG::char("\r\n \t"));
$zero = PEG::seq(PEG::char('0'));
$notzero = PEG::seq(PEG::char('123456789'), PEG::many(PEG::digit()));
$strnum = PEG::join(PEG::choice($notzero, $zero));
$num = PEG::hook('intval', PEG::first($strnum, $space));
$paren = PEG::second(PEG::seq('(', $space), PEG::ref($exp1), PEG::seq(')', $space));
$atom = PEG::choice($num, $paren);
$op = function($str) use($space) { return PEG::first(PEG::char($str), $space); };
$exp3 = PEG::memo($listof($atom, $op('/')));
$exp2 = PEG::memo($listof($exp3, $op('*')));
$exp1 = PEG::memo($listof($exp2, $op('+-')));
$exp = PEG::second($space, PEG::hook($torpn, $exp1), PEG::eos());
// 試してみる
var_dump($exp->parse(PEG::context('1 + 2 * 3'))); // => 1 2 3 * +
var_dump($exp->parse(PEG::context('(1 + 2) * 3'))); // => 1 2 + 3 *
var_dump($exp->parse(PEG::context('1 + 2 * 3 / 4'))); // => 1 2 3 4 / * +
var_dump($exp->parse(PEG::context('1 + 2 * 3 * 4'))); // => 1 2 3 * 4 * +