Write good parser in perl
Upcoming SlideShare
Loading in...5
×
 

Write good parser in perl

on

  • 3,316 views

 

Statistics

Views

Total Views
3,316
Views on SlideShare
2,753
Embed Views
563

Actions

Likes
1
Downloads
3
Comments
0

3 Embeds 563

http://d.hatena.ne.jp 556
http://localhost 4
http://webcache.googleusercontent.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Write good parser in perl Write good parser in perl Presentation Transcript

  • Write Good Parser in Perl Jiro Nishiguchi(西口次郎) id:spiritloose jiro@cpan.org Oct 15, 2010 YAPC::Asia Tokyo
  • BEGIN {} 1. $self introduction 2. パーサとは 3. Perlの代表的なパーサ 4. How to write parsers 5. まとめ
  • $self ● PAUSE ID: JIRO http://search.cpan.org/~jiro/ ● フリーランスのエンジニア ● Image::ObjectDetect ● Text::Migemo ● http://d.hatena.ne.jp/spiritloose/
  • Parserとは? ● なんらかの意味を持ったテキストを、その後の処理に適した 形にする。 ● 例(YAML):foo: bar → { foo => 'bar’ } ● 「正しく」「動作」して「あたりまえ」という期待 ● ソフトウェアの中での重要度は非常に高いはずだが… ● 空気のような存在 ● でもベンチはとられまくり ● かわいそうな子
  • Kind of parser? ● HTML / XML ● CSV / TSV ● JSON ● YAML ● Program (Perl, Ruby, Template-Toolkit, etc) ● Protocol (HTTP, SMTP, Memcached, etc) ● 業務データ
  • Perlでよく使うパーサ ● HTML::Parser ● XML::LibXML ● JSON, JSON::XS ● HTTP::Parser::XS ● Template-Toolkit ● Cache::Memcached
  • HTML::Parser ● Since 1996 ● Depended on by 408 modules ● ex. HTML::FIllInForm ● Written in XS ● 手書き(自前で1バイトずつ読み進める)
  • XML::LibXML ● Perl binding for libxml2 ● XMLの代表的なパーサ ● Depended on by 267 modules ● eg. Plagger
  • JSON(::PP) ● Standard JSON module ● Wrapper of JSON::PP and JSON::XS ● Pure Perlで手書き
  • JSON::XS ● 高速なJSONパーサ ● 手書き
  • HTTP::Parser::XS ● Plackで使われている ● Written in XS ● 手書き
  • Template-Toolkit ● Pure Perl ● Based on Parse::Yapp
  • Cache::Memcached ● get コマンドのパース ● ::GetParser ● ::GetParserXS (別ディストリビューション) ● 手書き
  • Why XS? ● Perlのテキスト処理は遅い(Cに比べて) ● 1バイトずつ読み進める処理はCが高速
  • How to write 1.既存のモジュールを使う 2.正規表現 3.Parser Generater をつかう 4.手書き
  • 手書き? ● 自由度は最も高い ● プログラマの腕によっては最高速になることも ● 一方で… ● バッファオーバーラン ● 漏れ ● (私のような) 怠惰なプログラマには向かない
  • 既存のモジュールを使う ● 重要! ● 既知のフォーマットで、ライブラリもそろっているのに自作す るといいことがあまりない ● バグを生みやすい ● 可能な限り新しいフォーマットを作らないのが重要
  • 正規表現ベース ● 書き捨て ● 規則が小さい、シンプル ● 誰にでも(Perlをかける人なら)分かりやすい ● Perlの正規表現は十分に速い ● 規則が大きくなってくるとメンテナンスが大変
  • Regexp::Assemble my $ra = Regexp::Assemble->new; $ra->add('^(incr|decr) ([^ ]+) (d+)( noreply)?$'); $ra->add('^(delete) ([^ ]+)( noreply)?$'); $ra->add('^(gets?) (.+)$'); $ra->re; # Optimized Regexp
  • Parser generator とは? ● 文法などの定義情報からパーサを生成する ● 怠惰なプログラマにうってつけ ● yacc(bison) ● Parse::Yapp ● Perse::Eyapp (Extended yapp) ● Perse::RecDecent ● Pegex ● Ragel
  • Ragel ● State Machine Compiler ● C, C++, Objective-C, D, Java and Ruby(no Perl?) ● BNF/Regexp に似た文法 ● RubyのMongrel(HTTP Server), Hprecot(HTML Parser) ● Graphvizでグラフを出力可能 ● ロバストなパーサを作りやすい ● ランタイムライブラリ不要 ● http://www.complang.org/ragel/
  • Ragel + XS ● ステートマシンの定義を書く ● パースする関数をCセクションに書く ● XSセクションではその関数を呼び出すだけ
  • Ragel + XS #include “xsutil.h” /* Module::Install::XSUtil */ %%{ # ステートマシン定義部 }%% static SV *parse(pTHX_ SV *text) { /* パーサに必要なデータ宣言 */ %% write init; %% write exec; return res; } MODULE = MyParser PACKAGE = MyParser SV *parse(SV *klass, SV *text) CODE: RETVAL = parse(aTHX_ text); OUTPUT: RETVAL
  • XSいやなんですけど… ● たいしたことしないので大丈夫です ● データ構造を作って返すだけ ● 文字列結合や、配列、ハッシュが触れればOK ● Perlでデータを加工したい場合は中間表現を返したり
  • 例:ログ解析(正規表現) our $RE = qr/([^ ]+) ([^ ])+ ([^ ]+) [([^]]+)] "([^"]+)" ([^ ]+) ([^ ]+)/; our @COLS = qw(host logname user time request status bytes); sub parse { my ($class, $line) = @_; if (my @matches = $line =~ $RE) { my %data; @data{@COLS} = @matches; return %data; } return; }
  • 例:ログ解析(Ragel) word = [^ ]+; host = word >begin_host %end_directive; logname = word >begin_logname %end_directive; user = word >begin_user %end_directive; time_fmt = [^]]+ >begin_time %end_directive; time = '[' time_fmt ']'; req_fmt = [^"]+ >begin_request %end_directive; request = '"' req_fmt '"'; status = word >begin_status %end_directive; bytes = word >begin_bytes %end_directive; main := host ' ' logname ' ' user ' ' time ' ' request ' ' status ' ' bytes;
  • Benchmark Ragel Pure Perl 0 50000 100000 150000 200000 250000 300000 Process per seconds
  • 例:Whitespace ● スペースとタブと改行だけで構成される言語 ● シンプルなスタックマシン ● 実は教育用によい?
  • Whitespace(Hello world)
  • Whitespace(Hello world) [S][S][S][T][S][S][T][S][S][S][LF] [S][S][S][S][S][T][T][S][T][T][T][T][LF] [T][LF] [T][LF] [S][S][S][S][S][T][T][S][S][T][S][T][LF] [S][S][S][S][S][T][T][T][S][S][T][S][LF] [T][LF] [T][LF] [S][S][S][S][S][T][T][S][T][T][S][S][LF] [S][S][S][S][S][T][T][S][T][T][S][S][LF] [T][LF] [T][LF] [S][S][S][S][S][T][T][S][T][T][S][S][LF] [S][S][S][S][S][T][T][S][S][T][S][S][LF] [T][LF] [T][LF] [S][S][S][S][S][T][T][S][T][T][T][T][LF] [S][S][S][S][S][T][S][S][S][S][T][LF] [T][LF] [T][LF] [S][S][S][S][S][T][S][T][T][S][S][LF] [S][S][S][S][S][T][S][T][S][LF] [T][LF] [T][LF] [S][S][S][S][S][T][S][S][S][S][S][LF] [S][S][LF] [T][LF] [LF] [S][S][S][S][S][T][T][T][S][T][T][T][LF] [LF] [T][LF]
  • Whitespace(disasm) PUSH 72 PUSH 111 PUTC PUTC PUSH 101 PUSH 114 PUTC PUTC PUSH 108 PUSH 108 PUTC PUTC PUSH 108 PUSH 100 PUTC PUTC PUSH 111 PUSH 33 PUTC PUTC PUSH 44 PUSH 10 PUTC PUTC PUSH 32 EXIT PUTC PUSH 119 PUTC
  • Whitespace add = tb sp sp sp >{ op = ADD; } %end_op; sub = tb sp sp tb >{ op = SUB; } %end_op; mul = tb sp sp lf >{ op = MUL; } %end_op; div = tb sp tb sp >{ op = DIV; } %end_op; mod = tb sp tb tb >{ op = MOD; } %end_op;
  • Graphviz %%{ machine test_parser; main := 'a' ('b' | 'c') 'd'+; }%% $ ragel -Vp test.rl | dot -Tpng > test.png
  • Perl6 ● パーサのための専用構文が用意された ● grammer ● 前述のRagelの例のようなことが built-inでできる ● Perl6のパーサも Perl6 の grammer で書かれている ● http://github.com/perl6/std/blob/master/STD.pm6
  • まとめ ● よく使われるPerlのパーサライブラリを紹介した ● パーサを書く場合の手法をいくつか紹介した ● 速度が求められる場合はCのパーサジェネレータ+XSを検 討してもよい ● 保守性と速度のトレードオフ
  • 【未承諾広告】求人 ● コミュニティサイト 2001年~ ● 5億pv / month ● 100 servers ● mod_perl + Sledge + MySQL ● Subversion + Redmine + Capistrano ● TheSchwartz, Memcached, Solr ● perlbrew, cpanm ● 私 <jiro@cpan.org> まで
  • END { thank_you(); } ● References ● http://www.slideshare.net/spiritloose ● http://github.com/spiritloose/ ● http://d.hatena.ne.jp/spiritloose/