SlideShare ist ein Scribd-Unternehmen logo
1 von 37
Downloaden Sie, um offline zu lesen
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/

Weitere ähnliche Inhalte

Was ist angesagt?

YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackcon
YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackconYATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackcon
YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackconHiroaki KOBAYASHI
 
いまさら聞けないRake入門
いまさら聞けないRake入門いまさら聞けないRake入門
いまさら聞けないRake入門Tomoya Kawanishi
 
CMSとPerlで遊ぼう
CMSとPerlで遊ぼうCMSとPerlで遊ぼう
CMSとPerlで遊ぼうDaiki Ichinose
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Ransui Iso
 
One - Common Lispでもワンライナーしたい
One - Common LispでもワンライナーしたいOne - Common Lispでもワンライナーしたい
One - Common Lispでもワンライナーしたいt-sin
 
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたOPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたYoshio Hanawa
 
Openjdk 入門してみた話
Openjdk 入門してみた話Openjdk 入門してみた話
Openjdk 入門してみた話Tokuhiro Matsuno
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方do_aki
 
PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)do_aki
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?2celeb
 
Ctb57 with god7
Ctb57 with god7Ctb57 with god7
Ctb57 with god7kingtomo
 
PHPの今とこれから2014
PHPの今とこれから2014PHPの今とこれから2014
PHPの今とこれから2014Rui Hirokawa
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説do_aki
 

Was ist angesagt? (20)

YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackcon
YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackconYATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackcon
YATT::Lite - PSGI を直接サポートしたテンプレートエンジン at #plackcon
 
Rでreproducible research
Rでreproducible researchRでreproducible research
Rでreproducible research
 
いまさら聞けないRake入門
いまさら聞けないRake入門いまさら聞けないRake入門
いまさら聞けないRake入門
 
CMSとPerlで遊ぼう
CMSとPerlで遊ぼうCMSとPerlで遊ぼう
CMSとPerlで遊ぼう
 
Scapy presentation
Scapy presentationScapy presentation
Scapy presentation
 
R3.0.0 is relased
R3.0.0 is relasedR3.0.0 is relased
R3.0.0 is relased
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
C-langage
C-langageC-langage
C-langage
 
One - Common Lispでもワンライナーしたい
One - Common LispでもワンライナーしたいOne - Common Lispでもワンライナーしたい
One - Common Lispでもワンライナーしたい
 
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたOPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
 
Openjdk 入門してみた話
Openjdk 入門してみた話Openjdk 入門してみた話
Openjdk 入門してみた話
 
Rake
RakeRake
Rake
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方
 
PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)PHP AST 徹底解説(補遺)
PHP AST 徹底解説(補遺)
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?
 
URLで遊ぼう
URLで遊ぼうURLで遊ぼう
URLで遊ぼう
 
Ctb57 with god7
Ctb57 with god7Ctb57 with god7
Ctb57 with god7
 
PHPの今とこれから2014
PHPの今とこれから2014PHPの今とこれから2014
PHPの今とこれから2014
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 

Ähnlich wie Write good parser in perl

2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talkmitamex4u
 
詳説ぺちぺち
詳説ぺちぺち詳説ぺちぺち
詳説ぺちぺちdo_aki
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法博文 斉藤
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
入門機械学習1,2章
入門機械学習1,2章入門機械学習1,2章
入門機械学習1,2章Kazufumi Ohkawa
 
データサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるデータサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるShintaro Fukushima
 
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜Hideo Kashioka
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいcharsbar
 
第一回Data mining勉強会 -第二章
第一回Data mining勉強会 -第二章第一回Data mining勉強会 -第二章
第一回Data mining勉強会 -第二章Tomonobu_Hirano
 
第一回Data mining勉強会 -第二章 - 原案
第一回Data mining勉強会 -第二章 - 原案第一回Data mining勉強会 -第二章 - 原案
第一回Data mining勉強会 -第二章 - 原案yushin_hirano
 
Impractical Introduction of Boost Spirit Qi [PPT]
Impractical Introduction of Boost Spirit Qi [PPT]Impractical Introduction of Boost Spirit Qi [PPT]
Impractical Introduction of Boost Spirit Qi [PPT]yak1ex
 
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」Hiro H.
 
XLWrapについてのご紹介
XLWrapについてのご紹介XLWrapについてのご紹介
XLWrapについてのご紹介Ohsawa Goodfellow
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexprGenya Murakami
 
知って得するC#
知って得するC#知って得するC#
知って得するC#Shota Baba
 

Ähnlich wie Write good parser in perl (20)

2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
 
詳説ぺちぺち
詳説ぺちぺち詳説ぺちぺち
詳説ぺちぺち
 
Tokyor23 doradora09
Tokyor23 doradora09Tokyor23 doradora09
Tokyor23 doradora09
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
入門機械学習1,2章
入門機械学習1,2章入門機械学習1,2章
入門機械学習1,2章
 
データサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるデータサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみる
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したい
 
第一回Data mining勉強会 -第二章
第一回Data mining勉強会 -第二章第一回Data mining勉強会 -第二章
第一回Data mining勉強会 -第二章
 
HiRoshimaR3_IntroR
HiRoshimaR3_IntroRHiRoshimaR3_IntroR
HiRoshimaR3_IntroR
 
第一回Data mining勉強会 -第二章 - 原案
第一回Data mining勉強会 -第二章 - 原案第一回Data mining勉強会 -第二章 - 原案
第一回Data mining勉強会 -第二章 - 原案
 
Impractical Introduction of Boost Spirit Qi [PPT]
Impractical Introduction of Boost Spirit Qi [PPT]Impractical Introduction of Boost Spirit Qi [PPT]
Impractical Introduction of Boost Spirit Qi [PPT]
 
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
 
XLWrapについてのご紹介
XLWrapについてのご紹介XLWrapについてのご紹介
XLWrapについてのご紹介
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 
知って得するC#
知って得するC#知って得するC#
知って得するC#
 

Write good parser in perl

  • 1. Write Good Parser in Perl Jiro Nishiguchi(西口次郎) id:spiritloose jiro@cpan.org Oct 15, 2010 YAPC::Asia Tokyo
  • 2. BEGIN {} 1. $self introduction 2. パーサとは 3. Perlの代表的なパーサ 4. How to write parsers 5. まとめ
  • 3. $self ● PAUSE ID: JIRO http://search.cpan.org/~jiro/ ● フリーランスのエンジニア ● Image::ObjectDetect ● Text::Migemo ● http://d.hatena.ne.jp/spiritloose/
  • 4. Parserとは? ● なんらかの意味を持ったテキストを、その後の処理に適した 形にする。 ● 例(YAML):foo: bar → { foo => 'bar’ } ● 「正しく」「動作」して「あたりまえ」という期待 ● ソフトウェアの中での重要度は非常に高いはずだが… ● 空気のような存在 ● でもベンチはとられまくり ● かわいそうな子
  • 5. Kind of parser? ● HTML / XML ● CSV / TSV ● JSON ● YAML ● Program (Perl, Ruby, Template-Toolkit, etc) ● Protocol (HTTP, SMTP, Memcached, etc) ● 業務データ
  • 6. Perlでよく使うパーサ ● HTML::Parser ● XML::LibXML ● JSON, JSON::XS ● HTTP::Parser::XS ● Template-Toolkit ● Cache::Memcached
  • 7. HTML::Parser ● Since 1996 ● Depended on by 408 modules ● ex. HTML::FIllInForm ● Written in XS ● 手書き(自前で1バイトずつ読み進める)
  • 8. XML::LibXML ● Perl binding for libxml2 ● XMLの代表的なパーサ ● Depended on by 267 modules ● eg. Plagger
  • 9. JSON(::PP) ● Standard JSON module ● Wrapper of JSON::PP and JSON::XS ● Pure Perlで手書き
  • 10. JSON::XS ● 高速なJSONパーサ ● 手書き
  • 11. HTTP::Parser::XS ● Plackで使われている ● Written in XS ● 手書き
  • 12. Template-Toolkit ● Pure Perl ● Based on Parse::Yapp
  • 13. Cache::Memcached ● get コマンドのパース ● ::GetParser ● ::GetParserXS (別ディストリビューション) ● 手書き
  • 14. Why XS? ● Perlのテキスト処理は遅い(Cに比べて) ● 1バイトずつ読み進める処理はCが高速
  • 16. 手書き? ● 自由度は最も高い ● プログラマの腕によっては最高速になることも ● 一方で… ● バッファオーバーラン ● 漏れ ● (私のような) 怠惰なプログラマには向かない
  • 17. 既存のモジュールを使う ● 重要! ● 既知のフォーマットで、ライブラリもそろっているのに自作す るといいことがあまりない ● バグを生みやすい ● 可能な限り新しいフォーマットを作らないのが重要
  • 18. 正規表現ベース ● 書き捨て ● 規則が小さい、シンプル ● 誰にでも(Perlをかける人なら)分かりやすい ● Perlの正規表現は十分に速い ● 規則が大きくなってくるとメンテナンスが大変
  • 19. Regexp::Assemble my $ra = Regexp::Assemble->new; $ra->add('^(incr|decr) ([^ ]+) (d+)( noreply)?$'); $ra->add('^(delete) ([^ ]+)( noreply)?$'); $ra->add('^(gets?) (.+)$'); $ra->re; # Optimized Regexp
  • 20. Parser generator とは? ● 文法などの定義情報からパーサを生成する ● 怠惰なプログラマにうってつけ ● yacc(bison) ● Parse::Yapp ● Perse::Eyapp (Extended yapp) ● Perse::RecDecent ● Pegex ● Ragel
  • 21. 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/
  • 22. Ragel + XS ● ステートマシンの定義を書く ● パースする関数をCセクションに書く ● XSセクションではその関数を呼び出すだけ
  • 23. 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
  • 24. XSいやなんですけど… ● たいしたことしないので大丈夫です ● データ構造を作って返すだけ ● 文字列結合や、配列、ハッシュが触れればOK ● Perlでデータを加工したい場合は中間表現を返したり
  • 25. 例:ログ解析(正規表現) 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; }
  • 26. 例:ログ解析(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;
  • 27. Benchmark Ragel Pure Perl 0 50000 100000 150000 200000 250000 300000 Process per seconds
  • 28. 例:Whitespace ● スペースとタブと改行だけで構成される言語 ● シンプルなスタックマシン ● 実は教育用によい?
  • 30. 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]
  • 31. 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
  • 32. 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;
  • 33. Graphviz %%{ machine test_parser; main := 'a' ('b' | 'c') 'd'+; }%% $ ragel -Vp test.rl | dot -Tpng > test.png
  • 34. Perl6 ● パーサのための専用構文が用意された ● grammer ● 前述のRagelの例のようなことが built-inでできる ● Perl6のパーサも Perl6 の grammer で書かれている ● http://github.com/perl6/std/blob/master/STD.pm6
  • 35. まとめ ● よく使われるPerlのパーサライブラリを紹介した ● パーサを書く場合の手法をいくつか紹介した ● 速度が求められる場合はCのパーサジェネレータ+XSを検 討してもよい ● 保守性と速度のトレードオフ
  • 36. 【未承諾広告】求人 ● コミュニティサイト 2001年~ ● 5億pv / month ● 100 servers ● mod_perl + Sledge + MySQL ● Subversion + Redmine + Capistrano ● TheSchwartz, Memcached, Solr ● perlbrew, cpanm ● 私 <jiro@cpan.org> まで
  • 37. END { thank_you(); } ● References ● http://www.slideshare.net/spiritloose ● http://github.com/spiritloose/ ● http://d.hatena.ne.jp/spiritloose/