非実用的  Boost Spirit Qi  入門 2011/5/14 Boost  勉強会 名古屋 @yak_ex /  新 康孝
自己紹介 <ul><li>氏名: 新 康孝  ( あたらし やすたか ) </li></ul><ul><li>Twitter ID: yak_ex </li></ul><ul><li>Web: http://yak3.myhome.cx:808...
Spirit  との馴れ初め <ul><li>PDF  用  Susie  プラグインがライセンスの 関係でずっと公開停止になってる </li></ul><ul><li>ライセンスの問題がない  PDF Susie  プラグインを作ろう! </...
Boost Spirit  とは? <ul><li>Boost  公式サイトの記述: </li></ul><ul><ul><li>LL parser framework represents parsers directly as EBNF g...
Boost Spirit  とは? <ul><li>世間での評判 </li></ul><ul><ul><li>変態 なことで有名な Boost::Spirit を… http://zo3kirin3.net/?p=82 </li></ul></...
これが  Spirit  の力だ! <ul><li>// #include  と  using namespace  省略 int main(void){   typedef std::map<std::string, std::string>...
高度に発達した C++ は魔法と区別がつかない アーサー・ C++ ・クラーク
Boost Spirit  とは? <ul><li>Boost  ライブラリの中でも最高峰の一つ(超私見) </li></ul><ul><ul><li>Optional, Variant, Fusion, Proto, Phoenix, MPL...
Spirit Qi  入門 <ul><li>Tutorial 嫁 </li></ul>
アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive を自作してみる </l...
Boost Spirit  とは? <ul><li>Boost  公式サイト: </li></ul><ul><ul><li>LL parser framework represents parsers directly as EBNF gram...
構文解析と  EBNF <ul><li>構文解析(文字列->データ構造) </li></ul><ul><ul><li>あるルールに則った文字列を解析 例: 式 </li></ul></ul>10 20 30 40 - * + 0 ( - 4 3...
構文解析と  EBNF <ul><li>EBNF = Extended Backus Normal Form </li></ul><ul><ul><li>「あるルール」=文法の表記方法 </li></ul></ul><ul><ul><ul><l...
Boost Spirit  の  rule <ul><li>EBNF による式の表現 </li></ul><ul><ul><li><Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* </li></ul>...
Boost Spirit  の  rule <ul><li>構成要素 </li></ul><ul><ul><li>Parser(基本要素) </li></ul></ul><ul><ul><li>Directive(修飾) </li></ul><...
Boost Spirit  の  rule <ul><li>Parser(基本要素) </li></ul>etc. 文字列  abc  を読む lit(“abc”) abc  いずれか 1 文字を読む char_(“abc”) a ~ b の範...
Boost Spirit  の  rule <ul><li>Directive (修飾:Parser の挙動を変える) </li></ul>etc. p  の  N  回の繰り返し repeat(N)[p] p  内部で大文字、小文字を区別しな...
Boost Spirit  の  rule <ul><li>Operator (結合) </li></ul>etc. p  が  0 or 1  回 -a b  でない  a a - b p  の  0  回以上の繰り返し *a 選択( a  ...
これが  Spirit  の力だ! <ul><li>// #include  と  using namespace  省略 int main(void){   typedef std::map<std::string, std::string>...
Boost Spirit  の  rule <ul><li>*(   lexeme[   *(   graph - char_('=')   )]   >> lit('=')   >> lexeme[   *graph ]) </li></ul...
で、出力は?
で、出力は? <ul><li>Parser  には「属性」があってその属性型の値を返す </li></ul><ul><ul><li>int_ -> int / char_ -> char </li></ul></ul><ul><li>修飾、結合...
で、出力は? <ul><li>pair  はアダプタによって  Fusion  シーケンスと見なせる ( ヘッダの  #include  が必要 ) </li></ul><ul><li>構造体も  Fusion  シーケンスと見なせる </li...
これが  Spirit  の力だ! <ul><li>//  #include   と  using namespace  省略 int main(void){   typedef std::map<std::string, std::strin...
出力先 <ul><li>lexeme  は  skip  の仕方が変わるだけで属性は変化しないので消す </li></ul><ul><li>lit  は無属性 (unused_type) 、 graph, char_  は char 、 pa ...
Spirit.Qi  入門 完 まだ  Spirit  の 変態フェイズは 終了してないぜ!!
アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive  を自作してみる </...
拡張性 <ul><li>Spirit (の変態性)を支える重要な要素 </li></ul><ul><ul><li>後から拡張できるような仕掛けがしてある </li></ul></ul><ul><ul><ul><li>Proto を使っているので...
Boost Spirit  の  rule  (再掲) <ul><li>Directive (修飾:Parser の挙動を変える) </li></ul>etc. p  の  N  回の繰り返し repeat(N)[p] p  内部で大文字、小文...
Directive  の自作 <ul><li>Parser  の自作は  boost-spirit.com  に記事有り http://bit.ly/ikdvQt </li></ul><ul><li>作る物:  delimited (delim...
Directive  の自作 <ul><li>自作コンポーネントの要素 </li></ul><ul><ul><li>終端記号の宣言 </li></ul></ul><ul><ul><li>Parser 本体の定義 </li></ul></ul><...
Directive  の自作 <ul><li>終端記号の宣言 namespace mine {   BOOST_SPIRIT_TERMINAL_EX( delimited ) } </li></ul>
Directive  の自作 <ul><li>Parser  本体 namespace mine {   //  内部  parser  が  1  つの  parser  型を定義  (CRTP  を利用 )   template<typen...
Directive  の自作 <ul><li>Parser  本体 namespace mine {   //  実際の解析ルーチン   template<typename Iterator, typename Context, typenam...
Directive  の自作 <ul><li>Parser generator  の定義 (rule -> Parser  の変換 )  namespace boost { namespace spirit { namespace qi {  ...
Directive  の自作 <ul><li>有効化 (Proto  に認識させる) namespace boost { namespace spirit {   //  通常用   template<typename Delimiter>  ...
Directive  の自作 <ul><li>// #include  と  using namespace  省略 int main(void){   typedef std::map<std::string, std::string> Co...
ね、簡単でしょう?
代替手段 <ul><li>引数 (Inherit attribute) 付きルールを定義 </li></ul><ul><li>rule<Iterator, std::string(std::string)> delimited; delimit...
非実用的入門
Customization point <ul><li>いちいち  Parser  とか  Directive  とか 作ってらんないけど挙動をカスタマイズしたい ->それ、 Spirit  ならできるよ! </li></ul><ul><li>...
Customization point <ul><li>boost::spirit::traits  以下に用意されている。 SFINAE  用の  Enabler  は省略 </li></ul><ul><ul><li>is_container...
Customization point  の関係 例)  Foo >> *Bar  の結果の戻し先として型  Qux  の変数  qux  が渡された場合    ※  Foo >> *Bar  の属性が  Qux  型であるとは限らない!   ...
Customization point  の関係 例)  Foo >> *Bar  の結果の戻し先として型  Qux  の変数  qux  が渡された場合    ※  Foo >> *Bar  の属性が  Qux  型であるとは限らない!   ...
アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive を自作してみる </l...
Spirit Qi  とうまく付き合うために <ul><li>コンパイル時間が Boost!!! </li></ul>  ->コーヒーでも飲んで優雅に待つといいよ! ※ axpdf--.spi  だとフルビルドに約  10  分 <ul><li...
Spirit Qi  とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul>
見えてる範囲 20% 縮小表示 画像補正しないと薄くて文字が 分からないレベル
Spirit Qi  とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul><ul><li>テンプレートのインスタンス化情報がほとんど </li></ul><ul><ul><l...
error  で検索 ココ 20% 縮小表示
Spirit Qi  とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul><ul><li>テンプレートのインスタンス化情報がほとんど </li></ul><ul><ul><l...
<ul><li>ケース 1. static_assert </li></ul><ul><ul><li>エラーメッセージ spirit7.cpp:30:  instantiated from here /usr/local/include/boo...
<ul><li>ケース 2.  コメント </li></ul><ul><ul><li>エラーメッセージ spirit7.cpp:39:  instantiated from here /usr/local/include/boost/spiri...
<ul><li>先生!コンパイル通ったけど思った通りに 動きません! </li></ul>Spirit Qi  とうまく付き合うために   ->プログラムは思った通りに動かない。    書いたとおりに動く。 <ul><li>debug(rule...
まとめ <ul><li>Spirit  は変態 </li></ul><ul><li>真面目に  Spirit  やりたい人は </li></ul><ul><li>Tutorial  を読みながら一通り実行する </li></ul><ul><li...
ご静聴ありがとうございました
Upcoming SlideShare
Loading in …5
×

Impractical Introduction of Boost Spirit Qi [PPT]

1,682
-1

Published on

for Boost Study Meeting #5 at Nagoya

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,682
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
16
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Impractical Introduction of Boost Spirit Qi [PPT]

  1. 1. 非実用的 Boost Spirit Qi 入門 2011/5/14 Boost 勉強会 名古屋 @yak_ex / 新 康孝
  2. 2. 自己紹介 <ul><li>氏名: 新 康孝 ( あたらし やすたか ) </li></ul><ul><li>Twitter ID: yak_ex </li></ul><ul><li>Web: http://yak3.myhome.cx:8080/junks </li></ul><ul><li>C++ / Perl が主戦場 </li></ul><ul><li>現在、仕事でコードに触れていないので 競技プログラミング( TopCoder 、 Codeforces )で 潤い補充 </li></ul><ul><li>闇の軍団に憧れるただの C++ 好き </li></ul><ul><ul><li>初めて Spirit 使った経験を元に発表 </li></ul></ul>
  3. 3. Spirit との馴れ初め <ul><li>PDF 用 Susie プラグインがライセンスの 関係でずっと公開停止になってる </li></ul><ul><li>ライセンスの問題がない PDF Susie プラグインを作ろう! </li></ul><ul><li>最低限、画像だけ抜いて来られればいいや </li></ul><ul><li>PDF フォーマットは割とテキストベース </li></ul><ul><li>構文解析が必要 </li></ul>※ プラグインは axpdf--.spi β 版として公開中 <ul><li>せっかくだから俺はこの Spirit を選ぶぜ! -> Spirit を初めて使用した経験を元に発表 </li></ul>
  4. 4. Boost Spirit とは? <ul><li>Boost 公式サイトの記述: </li></ul><ul><ul><li>LL parser framework represents parsers directly as EBNF grammars in inlined C++ </li></ul></ul><ul><ul><li>構文解析器を、 C++ 内で直接 EBNF 文法を書く事で作れるフレームワーク </li></ul></ul><ul><li>はぁ? </li></ul>
  5. 5. Boost Spirit とは? <ul><li>世間での評判 </li></ul><ul><ul><li>変態 なことで有名な Boost::Spirit を… http://zo3kirin3.net/?p=82 </li></ul></ul><ul><ul><li>変態 的と名高い (?) Boost.Spirit で解析。 http://ja.doukaku.org/comment/6518/ </li></ul></ul><ul><ul><li>… 同じく 変態 (褒め言葉)と名高い boost::spirit を使って実装することにした。 http://d.hatena.ne.jp/Hossy/20080407 </li></ul></ul>結論: Boost Spirit = 変態
  6. 6. これが Spirit の力だ! <ul><li>// #include と using namespace 省略 int main(void){ typedef std::map<std::string, std::string> Config; Config config; std::string input(&quot;Boost.Spirit = extraordinary n C++er = ...&quot;); phrase_parse(input.begin(), input.end(), *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph]), space, config); BOOST_FOREACH(Config::value_type &kv, config) { std::cout << kv.first << '=' << kv.second << std::endl; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>出力 Boost.Spirit=extraordinary C++er=... </li></ul><key>=<value> が std::map に突っ込まれる 型と出力変数定義 入力定義 出力 へ ん た い
  7. 7. 高度に発達した C++ は魔法と区別がつかない アーサー・ C++ ・クラーク
  8. 8. Boost Spirit とは? <ul><li>Boost ライブラリの中でも最高峰の一つ(超私見) </li></ul><ul><ul><li>Optional, Variant, Fusion, Proto, Phoenix, MPL 等、 他の Boost ライブラリをふんだんに使用 </li></ul></ul><ul><ul><li>C++ でできることのベンチマーク的位置づけ </li></ul></ul><ul><ul><ul><li>どんなものか知っとくだけでも意味はあるかと </li></ul></ul></ul><ul><li>Qi, Karma, Lex で構成 </li></ul><ul><ul><li>Qi: 構文解析(文字列->データ構造) </li></ul></ul><ul><ul><li>Karma : 出力(データ構造->文字列) </li></ul></ul><ul><ul><li>Lex : 字句解析(文字列->トークン列) </li></ul></ul>← 今回のテーマ
  9. 9. Spirit Qi 入門 <ul><li>Tutorial 嫁 </li></ul>
  10. 10. アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive を自作してみる </li></ul></ul><ul><ul><li>Customization point </li></ul></ul><ul><li>蛇足 </li></ul>
  11. 11. Boost Spirit とは? <ul><li>Boost 公式サイト: </li></ul><ul><ul><li>LL parser framework represents parsers directly as EBNF grammars in inlined C++ </li></ul></ul><ul><ul><li>構文解析器を、 C++ 内で直接 EBNF 文法を書く 事で作れるフレームワーク </li></ul></ul>
  12. 12. 構文解析と EBNF <ul><li>構文解析(文字列->データ構造) </li></ul><ul><ul><li>あるルールに則った文字列を解析 例: 式 </li></ul></ul>10 20 30 40 - * + 0 ( - 4 3 0 0 * ) 2 + 0 1
  13. 13. 構文解析と EBNF <ul><li>EBNF = Extended Backus Normal Form </li></ul><ul><ul><li>「あるルール」=文法の表記方法 </li></ul></ul><ul><ul><ul><li>選択 | </li></ul></ul></ul><ul><ul><ul><li>0回以上の繰り返し *、1回以上の繰り返し + </li></ul></ul></ul><ul><ul><li>例: 式 </li></ul></ul><ul><ul><ul><li><Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* </li></ul></ul></ul><ul><ul><ul><li><Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* </li></ul></ul></ul><ul><ul><ul><li><Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’ </li></ul></ul></ul>
  14. 14. Boost Spirit の rule <ul><li>EBNF による式の表現 </li></ul><ul><ul><li><Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* </li></ul></ul><ul><ul><li><Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* </li></ul></ul><ul><ul><li><Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’ </li></ul></ul>C++ の式として有効 <ul><li>Spirit での式の表現 </li></ul><ul><ul><li>expr = term >> *(char_(“+-”) >> term); </li></ul></ul><ul><ul><li>term = factor >> *(char_(“*/”) >> factor); </li></ul></ul><ul><ul><li>factor = int_ | lit(‘(‘) >> expr >> lit(‘)’); </li></ul></ul>
  15. 15. Boost Spirit の rule <ul><li>構成要素 </li></ul><ul><ul><li>Parser(基本要素) </li></ul></ul><ul><ul><li>Directive(修飾) </li></ul></ul><ul><ul><li>Operator(結合) </li></ul></ul>
  16. 16. Boost Spirit の rule <ul><li>Parser(基本要素) </li></ul>etc. 文字列 abc を読む lit(“abc”) abc いずれか 1 文字を読む char_(“abc”) a ~ b の範囲の 1 文字を読む char_(‘a’, ‘b’) isgraph() が true な 1 文字を読む graph a 1 文字を読む lit(‘a’) 整数値を読む int_ 任意の 1 文字を読む char_
  17. 17. Boost Spirit の rule <ul><li>Directive (修飾:Parser の挙動を変える) </li></ul>etc. p の N 回の繰り返し repeat(N)[p] p 内部で大文字、小文字を区別しない no_case[p] p の N 回以上の繰り返し repeat(N,inf)[p] p の N ~ M 回の繰り返し repeat(N,M)[p] p 先頭で空白をスキップ、 p 内部では空白をスキップしない lexeme[p]
  18. 18. Boost Spirit の rule <ul><li>Operator (結合) </li></ul>etc. p が 0 or 1 回 -a b でない a a - b p の 0 回以上の繰り返し *a 選択( a あるいは b ) a | b b で区切られた a の繰り返し a % b p の 1 回以上の繰り返し +a 連接(普通に繋げる) a >> b
  19. 19. これが Spirit の力だ! <ul><li>// #include と using namespace 省略 int main(void){ typedef std::map<std::string, std::string> Config; Config config; std::string input(&quot;Boost.Spirit = extraordinary n C++er = ...&quot;); phrase_parse(input.begin(), input.end(), *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph]), space, config); BOOST_FOREACH(Config::value_type &kv, config) { std::cout << kv.first << '=' << kv.second << std::endl; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>出力 Boost.Spirit=extraordinary C++er=... </li></ul><key>=<value> が std::map に突っ込まれる へ ん た い
  20. 20. Boost Spirit の rule <ul><li>*( lexeme[ *( graph - char_('=') )] >> lit('=') >> lexeme[ *graph ]) </li></ul>0 回以上の繰り返し 内部スキップなし 0 回以上の繰り返し = 以外の表示文字 = 内部スキップなし 表示文字の 0 回以上の繰り返し <key>=<value> の繰り返し
  21. 21. で、出力は?
  22. 22. で、出力は? <ul><li>Parser には「属性」があってその属性型の値を返す </li></ul><ul><ul><li>int_ -> int / char_ -> char </li></ul></ul><ul><li>修飾、結合されたものは? </li></ul><ul><li>-> Fusion シーケンス or STL コンテナが属性になる </li></ul><ul><ul><li>char_ >> int_ >> double_ -> tuple<char, int, double> </li></ul></ul><ul><ul><li>*int_ -> vector<int> </li></ul></ul><ul><ul><li>int_ >> int_ は? -> どっちでも OK </li></ul></ul>※ tuple, vector は代表で Fusion シーケンス / コンテナなら何でも良い ※ 詳細は「 Quick Reference 」 の「 Compound Attribute Rules 」を参照
  23. 23. で、出力は? <ul><li>pair はアダプタによって Fusion シーケンスと見なせる ( ヘッダの #include が必要 ) </li></ul><ul><li>構造体も Fusion シーケンスと見なせる </li></ul><ul><ul><li>BOOST_FUSION_ADAPT_STRUCT </li></ul></ul><ul><ul><li>BOOST_FUSION_DEFINE_STRUCT で 構造体定義と ADAPT を一気にできる </li></ul></ul>※ Fusion は前回勉強会の cpp_akira さんの発表も参照 BOOST_FUSION_DEFINE_STRUCT( (yak)(pdf), indirect_ref, (int, number) (int, generation) ) 構造体 yak::pdf::indirect_ref が tuple<int, int> 相当になる
  24. 24. これが Spirit の力だ! <ul><li>// #include と using namespace 省略 int main(void){ typedef std::map<std::string, std::string> Config; Config config; std::string input(&quot;Boost.Spirit = extraordinary n C++er = ...&quot;); phrase_parse(input.begin(), input.end(), *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph]), space, config ); BOOST_FOREACH(Config::value_type &kv, config) { std::cout << kv.first << '=' << kv.second << std::endl; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>出力 Boost.Spirit=extraordinary C++er=... </li></ul><key>=<value> が std::map に突っ込まれる へ ん た い
  25. 25. 出力先 <ul><li>lexeme は skip の仕方が変わるだけで属性は変化しないので消す </li></ul><ul><li>lit は無属性 (unused_type) 、 graph, char_ は char 、 pa – pb は pa の属性 </li></ul><ul><li>vector<tuple<vector<char>, vector<char> > > or vector<vector<char> > </li></ul>※ vector<char> と string は互換 ->これらも互換 *(*(graph - char_('=')) >> lit('=') >> *graph) *(*char >> *char) <ul><li>std::map<std::string, std::string> </li></ul><ul><li>std::pair<std::string, std::string> のコンテナ </li></ul><ul><li>std::string, std::string の Fusion シーケンスのコンテナ </li></ul>Rule の属性 代入先 *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph])
  26. 26. Spirit.Qi 入門 完 まだ Spirit の 変態フェイズは 終了してないぜ!!
  27. 27. アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive を自作してみる </li></ul></ul><ul><ul><li>Customization point </li></ul></ul><ul><li>蛇足 </li></ul>
  28. 28. 拡張性 <ul><li>Spirit (の変態性)を支える重要な要素 </li></ul><ul><ul><li>後から拡張できるような仕掛けがしてある </li></ul></ul><ul><ul><ul><li>Proto を使っているので自前のコンポーネント(Parser等)を作成できる ->Directive の自作 </li></ul></ul></ul><ul><ul><ul><li>処理にフックが用意してある ->Customization point </li></ul></ul></ul>
  29. 29. Boost Spirit の rule (再掲) <ul><li>Directive (修飾:Parser の挙動を変える) </li></ul>etc. p の N 回の繰り返し repeat(N)[p] p 内部で大文字、小文字を区別しない no_case[p] p の N 回以上の繰り返し repeat(N,inf)[p] p の N ~ M 回の繰り返し repeat(N,M)[p] p 先頭で空白をスキップ、 p 内部では空白をスキップしない lexeme[p]
  30. 30. Directive の自作 <ul><li>Parser の自作は boost-spirit.com に記事有り http://bit.ly/ikdvQt </li></ul><ul><li>作る物: delimited (delimiter)[parser] </li></ul><ul><ul><li>例: delimited(std::string(“endstream”))[char_] endstream という文字列にぶつかるまで char を読み出す </li></ul></ul><ul><ul><li>せっかくなので char 非限定で作成 </li></ul></ul><ul><ul><ul><li>std::vector<int> delim(2, -1); delimited(delim)[int_] で -1 -1 にぶつかるまで int を読み出す </li></ul></ul></ul>
  31. 31. Directive の自作 <ul><li>自作コンポーネントの要素 </li></ul><ul><ul><li>終端記号の宣言 </li></ul></ul><ul><ul><li>Parser 本体の定義 </li></ul></ul><ul><ul><ul><li>属性の型 </li></ul></ul></ul><ul><ul><ul><li>実際の解析処理 </li></ul></ul></ul><ul><ul><li>Parser generator の定義(rule -> Parser の変換) </li></ul></ul><ul><ul><li>有効化 </li></ul></ul><ul><ul><ul><li>コンポーネント自身 </li></ul></ul></ul><ul><ul><ul><li>Semantic action </li></ul></ul></ul>※ 今回 semantic action には全く触れませんので Tutorial 参照
  32. 32. Directive の自作 <ul><li>終端記号の宣言 namespace mine { BOOST_SPIRIT_TERMINAL_EX( delimited ) } </li></ul>
  33. 33. Directive の自作 <ul><li>Parser 本体 namespace mine { // 内部 parser が 1 つの parser 型を定義 (CRTP を利用 ) template<typename Subject , typename Delimiter> struct delimited_parser : boost::spirit::qi::unary_parser<delimited_parser< Subject , Delimiter> > { // メンバテンプレートクラス attribute を定義( type が 属性の型 ) template <typename Context, typename Iterator> struct attribute { typedef typename boost::spirit::traits::build_std_vector< typename boost::spirit::traits::attribute_of<Subject, Context, Iterator>::type >::type type ; }; // コンストラクタ( parser generator から呼ばれる) delimited_parser( Subject const &subject, Delimiter const &delimiter) : subject(subject), delimiter(delimiter) {} </li></ul>※ Directive 内部の Parser の型 delimited(delimiter)[parser]
  34. 34. Directive の自作 <ul><li>Parser 本体 namespace mine { // 実際の解析ルーチン template<typename Iterator, typename Context, typename Skipper, typename Attribute> bool parse (Iterator &first, Iterator const &last, Context &context, Skipper const &skipper, Attribute &attribute) const { // 詳細略 subject.parse() を使って KMP 法的に処理。 // 汎用的にやるならコンテナ操作には traits を使う。 // traits::container_value<Attribute>::type // traits::container_iterator<const Delimiter>::type // traits::begin(delimiter); } template <typename Context> boost::spirit::info what(Context& context) const { return boost::spirit::info(“delimited”, subject.what(context)); } Subject subject; // Directive 内部のパーサー保持用 Delimiter delimiter; // デリミタ保持用 }; </li></ul>※ 属性
  35. 35. Directive の自作 <ul><li>Parser generator の定義 (rule -> Parser の変換 ) namespace boost { namespace spirit { namespace qi { template <typename Delimiter, typename Subject, typename Modifiers> struct make_directive < terminal_ex<mine::tag:: delimited , fusion::vector1<Delimiter> >, Subject, Modifiers> { // Parser の型 typedef mine:: delimited_parser <Subject, Delimiter> result_type ; // Parser を返す operator() template <typename Terminal> </li></ul><ul><li>result_type operator() (Terminal const& term, Subject const& subject, unused_type) const { return result_type(subject, fusion::at_c<0>(term.args) ); } }; }}} </li></ul>引数の 0 番目要素 Directive の引数の型: Delimiter 1 つ delimited (delimiter) [parser] Parser の コンストラクタ呼び出し
  36. 36. Directive の自作 <ul><li>有効化 (Proto に認識させる) namespace boost { namespace spirit { // 通常用 template<typename Delimiter> struct use_directive <qi::domain, terminal_ex<mine::tag:: delimited , fusion::vector1<Delimiter> > > : mpl::true_ {}; // Phoenix (Lambda みたいなもの ) 用 template<> struct use_lazy_directive <qi::domain, mine::tag::delimited, 1 // arity > : mpl::true_ {}; </li></ul>
  37. 37. Directive の自作 <ul><li>// #include と using namespace 省略 int main(void){ typedef std::map<std::string, std::string> Config; Config config; std::string input(&quot;Boost.Spirit= extraordinary n C++er= ...&quot;); phrase_parse(input.begin(), input.end(), *(lexeme[ delimited(std::string(“=“))[graph] ] >> lexeme[*graph]), space, config); BOOST_FOREACH(Config::value_type &kv, config) { std::cout << kv.first << '=' << kv.second << std::endl; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>出力 Boost.Spirit=extraordinary C++er=... </li></ul>※ 入力を微妙に変更
  38. 38. ね、簡単でしょう?
  39. 39. 代替手段 <ul><li>引数 (Inherit attribute) 付きルールを定義 </li></ul><ul><li>rule<Iterator, std::string(std::string)> delimited; delimited = *(graph_ - _r1) >> omit[_r1]; </li></ul><ul><li>使い方 phrase_parse(input.begin(), input.end(), *(lexeme[ delimited(“=“) ] >> lexeme[*graph]), space, config); </li></ul>引数 引数 値を捨てる 引数の型 属性
  40. 40. 非実用的入門
  41. 41. Customization point <ul><li>いちいち Parser とか Directive とか 作ってらんないけど挙動をカスタマイズしたい ->それ、 Spirit ならできるよ! </li></ul><ul><li>traits を特殊化することで挙動を変更 </li></ul>
  42. 42. Customization point <ul><li>boost::spirit::traits 以下に用意されている。 SFINAE 用の Enabler は省略 </li></ul><ul><ul><li>is_container<Container> >> 系用 </li></ul></ul><ul><ul><ul><li>関連: container_value<Container> etc. </li></ul></ul></ul><ul><ul><li>handles_container<Component, Attr> >> 系用 </li></ul></ul><ul><ul><li>transform_attribute<Exposed, Transformed, Domain> rule 系用 </li></ul></ul><ul><ul><li>assign_to_attribute_from_iterators<Attr, Iterator> 汎用 </li></ul></ul><ul><ul><li>assign_to_attribute_from_value<Attr, T> 汎用 </li></ul></ul><ul><ul><li>assign_to_container_from_value<Attr, T> 汎用 </li></ul></ul><ul><ul><li>push_back_container<Container, Attr> 繰返系用 </li></ul></ul><ul><ul><li>clear_value<Attr> 繰返系用 </li></ul></ul><ul><ul><li>etc. </li></ul></ul><ul><ul><li>create_parser<T> auto_ 用 cf. http://slashdot.jp/~Yak!/journal/525693 </li></ul></ul>
  43. 43. Customization point の関係 例) Foo >> *Bar の結果の戻し先として型 Qux の変数 qux が渡された場合    ※ Foo >> *Bar の属性が Qux 型であるとは限らない!    ※ 大枠だけ図示、 ::type や ::call も省略 is_container<Qux> handles_container<Foo> handles_container<*Bar> push_back_container<Qux,Foo_temp>(qux, foo_temp); foo_temp ← Foo 読み出し container_value<Qux>::type foo_temp; true true qux ← Foo 読み出し false true qux ← *Bar 読み出し ※ * ならデフォルト true   false なら↑と同様の処理 clear_value<Bar> push_back_container<Qux,Bar_attr> を内部で利用
  44. 44. Customization point の関係 例) Foo >> *Bar の結果の戻し先として型 Qux の変数 qux が渡された場合    ※ Foo >> *Bar の属性が Qux 型であるとは限らない!    ※ 大枠だけ図示、 ::type や ::call も省略 is_container<Qux> is_container<QA> transform_attribute<QA, Foo_attr>::type foo_temp = transform_attribute<QA, Foo_attr>::pre(qa); false true 前ページと同様の処理 false Qux は 2 要素の Fusion シーケンス tuple<QA, QB> とする foo_temp ← Foo 読み出し transform_attribute<QA, Foo_attr>::post(qa, foo_temp); QB と *Bar の属性について上と同様の処理 Foo は何? rule や attr_cast Foo_attr foo_temp; 他 ※ デフォルトは内部で assign_to を使用 ※ 内部で assign_to_* 族を使用 assign_to(foo_temp, qa); foo_temp ← Foo 読み出し
  45. 45. アジェンダ <ul><li>概要紹介 </li></ul><ul><ul><li>限定された使い方のみ </li></ul></ul><ul><li>拡張性 </li></ul><ul><ul><li>Directive を自作してみる </li></ul></ul><ul><ul><li>Customization point </li></ul></ul><ul><li>蛇足 </li></ul>
  46. 46. Spirit Qi とうまく付き合うために <ul><li>コンパイル時間が Boost!!! </li></ul>  ->コーヒーでも飲んで優雅に待つといいよ! ※ axpdf--.spi だとフルビルドに約 10 分 <ul><li>Spirit 関連部分を分離して文法が変わらない限り再コンパイル不要にする </li></ul><ul><ul><li>Parser はあくまで parser に徹して 構文解析結果に対する処理は別に分けるとか </li></ul></ul>
  47. 47. Spirit Qi とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul>
  48. 48. 見えてる範囲 20% 縮小表示 画像補正しないと薄くて文字が 分からないレベル
  49. 49. Spirit Qi とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul><ul><li>テンプレートのインスタンス化情報がほとんど </li></ul><ul><ul><li>まずは error で検索 </li></ul></ul>
  50. 50. error で検索 ココ 20% 縮小表示
  51. 51. Spirit Qi とうまく付き合うために <ul><li>エラーメッセージ量が Boost!!! ->例: 3.3MB </li></ul><ul><li>テンプレートのインスタンス化情報がほとんど </li></ul><ul><ul><li>まずは error で検索 </li></ul></ul><ul><ul><li>後はどこが真因かインスタンス化情報を遡る…前に </li></ul></ul><ul><ul><li>一度エラー箇所を見てみるといいことがあるかも </li></ul></ul>
  52. 52. <ul><li>ケース 1. static_assert </li></ul><ul><ul><li>エラーメッセージ spirit7.cpp:30: instantiated from here /usr/local/include/boost/spirit/home/qi/nonterminal/grammar.hpp:75: error: no matching function for call to ‘assertion_failed( mpl_::failed************ (boost::spirit::qi::grammar<Iterator, T1, T2, T3, T4>::grammar(const boost::spirit::qi::rule<Iterator_, T1_, T2_, T3_, T4_>&, const std::string&) [ 何か一杯 ]:: incompatible_start_rule::************ )( 何か一杯 ))’ </li></ul></ul>Spirit Qi とうまく付き合うために
  53. 53. <ul><li>ケース 2. コメント </li></ul><ul><ul><li>エラーメッセージ spirit7.cpp:39: instantiated from here /usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:277: error: no match for call to ‘ 何か一杯’ </li></ul></ul><ul><ul><li>/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp // If you are seeing a compilation error here stating that the // forth parameter can't be converted to a required target type // then you are probably trying to use a rule or a grammar with // an incompatible skipper type. if (f(first, last, context, skipper)) </li></ul></ul>Spirit Qi とうまく付き合うために 277 行目
  54. 54. <ul><li>先生!コンパイル通ったけど思った通りに 動きません! </li></ul>Spirit Qi とうまく付き合うために   ->プログラムは思った通りに動かない。   書いたとおりに動く。 <ul><li>debug(rule); を使うと構文解析の様子がトレース できる http://boost- spirit.com /home/articles/doc-addendum/debugging/ </li></ul><ul><ul><li>属性に operator<< が必要 </li></ul></ul>
  55. 55. まとめ <ul><li>Spirit は変態 </li></ul><ul><li>真面目に Spirit やりたい人は </li></ul><ul><li>Tutorial を読みながら一通り実行する </li></ul><ul><li>boost-spirit.com の記事を読む </li></ul><ul><li>随時 Quick Reference を参照する </li></ul>
  56. 56. ご静聴ありがとうございました
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×