SSブログ

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


nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

SML# 0.20 から Tcl を呼ぶRuby による LFG ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。