Created
May 28, 2021 23:21
-
-
Save todays-mitsui/814e0b80eeb0665e75104a659724217f to your computer and use it in GitHub Desktop.
Parsica デモ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"require": { | |
"parsica-php/parsica": "^0.8.1" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Parsica\Parsica\Parser; | |
use function Parsica\Parsica\{ | |
between, | |
char, | |
collect, | |
either, | |
integer, | |
recursive, | |
}; | |
require(__DIR__."/vendor/autoload.php"); | |
/** | |
* 整式を前置記法で表記する | |
* | |
* @param array|int $ast | |
* @return string | |
*/ | |
function prefix_notation($ast) | |
{ | |
if (!is_array($ast)) { return $ast; } | |
$operator = $ast["operator"]; | |
$left = prefix_notation($ast["left"]); | |
$right = prefix_notation($ast["right"]); | |
return "{$operator} {$left} {$right}"; | |
} | |
/** | |
* 整式を後置記法で表記する | |
* | |
* @param array|int $ast | |
* @return string | |
*/ | |
function postfix_notation($ast) | |
{ | |
if (!is_array($ast)) { return $ast; } | |
$operator = $ast["operator"]; | |
$left = postfix_notation($ast["left"]); | |
$right = postfix_notation($ast["right"]); | |
return "{$left} {$right} {$operator}"; | |
} | |
function main() | |
{ | |
// 各種のパーサを定義 | |
// <expression> := <term> [ "+" <expression> ] | |
// <term> := <factor> [ "*" <term> ] | |
// <factor> := <number> | "(" <expression> ")" | |
/** @var Parser<int> */ | |
$pNumber = integer()->map("intval")->label("number"); | |
/** @var Parser<array> */ | |
$pExpression = recursive()->label("expression"); | |
/** @var Parser<array> */ | |
$pTerm = recursive()->label("term"); | |
/** @var Parser<array> */ | |
$pFactor = recursive()->label("factor"); | |
$pExpression->recurse( | |
either( | |
collect($pTerm, char("+"), $pExpression) | |
->map(fn(array $vals) => [ | |
"operator" => $vals[1], | |
"left" => $vals[0], | |
"right" => $vals[2], | |
]) | |
, | |
$pTerm | |
) | |
); | |
$pTerm->recurse( | |
either( | |
collect($pFactor, char("*"), $pTerm) | |
->map(fn(array $vals) => [ | |
"operator" => $vals[1], | |
"left" => $vals[0], | |
"right" => $vals[2], | |
]) | |
, | |
$pFactor | |
) | |
); | |
$pFactor->recurse( | |
either( | |
$pNumber, | |
between(char("("), char(")"), $pExpression) | |
) | |
); | |
// 中置記法で書いた式 | |
$infix_notation = "2*(3+4)+5"; | |
// 抽象構文木 (AST) に変換 | |
$ast = $pExpression->tryString($infix_notation)->output(); | |
// => [ | |
// "operator" => "+", | |
// "operator" => "*", | |
// "left" => 2, | |
// "right" => [ | |
// "operator" => "+", | |
// "left" => 3, | |
// "right" => 4, | |
// ], | |
// ], | |
// "right" => 5, | |
// ] | |
// 前置記法で出力 | |
echo prefix_notation($ast) . "\n"; // => "+ * 2 + 3 4 5" | |
// 後置記法で出力 | |
echo postfix_notation($ast) . "\n"; // => "2 3 4 + * 5 +" | |
} | |
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use function Parsica\Parsica\{ | |
assemble, | |
atLeastOne, | |
char, | |
everything, | |
integer, | |
noneOfS, | |
optional, | |
string, | |
}; | |
require(__DIR__."/vendor/autoload.php"); | |
// URI を Scheme, Host, Path などに分解する | |
// parse_url() 相当の処理 | |
// 各パーツのパーサを作っていく | |
$pScheme = string("http") | |
->append(optional(char("s"))) | |
->map(fn($val) => [ "scheme" => $val ]); | |
$pUserinfo = atLeastOne(noneOfS(":@")) | |
->append(char(":")) | |
->append(atLeastOne(noneOfS("@"))) | |
->thenIgnore(char("@")) | |
->map(fn($val) => [ "userinfo" => $val ]); | |
$pHost = atLeastOne(noneOfS(":/")) | |
->map(fn($val) => [ "host" => $val ]); | |
$pPort = char(":")->followedBy(integer()) | |
->map(fn($val) => [ "port" => $val ]); | |
$pPath = atLeastOne(noneOfS("?")) | |
->map(fn($val) => [ "path" => $val ]); | |
$pQuery = char("?") | |
->append(atLeastOne(noneOfS("#"))) | |
->map(fn($val) => [ "query" => $val ]); | |
$pFragment = char("#") | |
->append(everything()) | |
->map(fn($val) => [ "fragment" => $val ]); | |
// 小さなパーサを組み合わせて URI 用のパーサを作る | |
$pUri = assemble( | |
$pScheme, | |
string("://")->map(fn($_) => null), | |
optional($pUserinfo), | |
$pHost, | |
optional($pPort), | |
optional($pPath), | |
optional($pQuery), | |
optional($pFragment) | |
); | |
var_dump($pUri->tryString("https://example.com/")->output()); | |
// => [ | |
// "scheme" => "https", | |
// "host" => "example.com", | |
// "path" => "/", | |
// ] | |
var_dump($pUri->tryString("https://username:path@example.com:8080/a/b/c/?key=val#target")->output()); | |
// => [ | |
// "scheme" => "https", | |
// "userinfo" => "username:path", | |
// "host" => "example.com", | |
// "port" => "8080", | |
// "path" => "/a/b/c/", | |
// "query" => "?key=val", | |
// "fragment" => "#target", | |
// ] | |
var_dump($pUri->tryString("https//example.com/")->output()); | |
// => Uncaught Parsica\Parsica\ParserHasFailed: <input>:1:6 | |
// | | |
// 1 | ...//example.com/ | |
// | ^— column 6 | |
// Unexpected <slash> | |
// Expecting '://' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment