Parse::RecDescent で JSON パーサを作る [Perl]
Parse::RecDescent [1] は yacc 風の文法定義を与えるとパーサを生成してくれる Perl モジュール。
ドキュメントが長文だけど、取りあえず
- 字句解析に相当するものは文字列リテラルか正規表現をそのまま。
- ルールは 識別子: サブルール { アクション } の形で書く。
- アクションの中の Perl コードでは $item[1], $item[2] ... が yacc でいう $1, $2 ... に相当する。
- サブルールの後に (?), (s), (s?) をつけると正規表現で言う ?, +, * の意味になる。
- subrule(s? /,/) のようにして繰り返しの中のセパレータを指定できる。(この場合は subrule が0回以上繰り返され、間にカンマが入るという意味)
- アクションの中で $return 変数に値を入れるとそれがそのプロダクションの値になる。
これらの点を抑えておけば大体のことはできそうだと思う。
手始めに JSON パーサを書いてみた。(string と number のところの正規表現は相当さぼっている)
use Parse::RecDescent;
$grammar = q(
object : "{" pair(s? /,/) "}"
{
my %obj;
foreach my $i (@{$item[2]}) {
$obj{$i->[0]} = $i->[1];
}
$return = \%obj;
}
pair : string ":" value
{ $return = [$item[1], $item[3]]; }
array : "{" value(s? /,/) "}"
{ $return = $item[2]; }
value : string | number | object | array | true | false | null
{ $return = $item[1]; }
string : /\"\w+\"/
{ $item[1] =~ /\"(\w+)\"/; $return = $1; }
number : /\d+/
{ $return = $item[1]; }
true : "true"
{ $return = 1; }
false : "false"
{ $return = 0; }
null : "null"
{ $return = undef; }
);
$parser = new Parse::RecDescent ($grammar) or die "Bad grammar!\n";
$text = <<TEXT;
{
"abc" :
{
"def" : "Hello",
"ghi" : {1, 3, 5}
}
}
TEXT
$result = $parser->object($text);
$result or print "Bad text!\n";
print $result->{"abc"}->{"def"}."\n"; #=> Hello
foreach my $i (@{$result->{"abc"}->{"ghi"} }) {
print "$i\n";
}
#=> 1, 3, and 5
これは便利だ。
[1] http://search.cpan.org/~dconway/Parse-RecDescent-1.94/lib/Parse/RecDescent.pod
コメント 0