狠狠撸

狠狠撸Share a Scribd company logo
非実用的  Boost Spirit Qi  入門 2011/5/14 Boost  勉強会 名古屋 @yak_ex /  新 康孝
自己紹介 氏名: 新 康孝  ( あたらし やすたか ) Twitter ID: yak_ex Web: http://yak3.myhome.cx:8080/junks C++ / Perl  が主戦場 現在、仕事でコードに触れていないので 競技プログラミング( TopCoder 、 Codeforces )で 潤い補充 闇の軍団に憧れるただの  C++  好き 初めて  Spirit  使った経験を元に発表
Spirit  との馴れ初め PDF  用  Susie  プラグインがライセンスの 関係でずっと公開停止になってる ライセンスの問題がない  PDF Susie  プラグインを作ろう! 最低限、画像だけ抜いて来られればいいや PDF  フォーマットは割とテキストベース 構文解析が必要 ※ プラグインは  axpdf--.spi β 版として公開中 せっかくだから俺はこの  Spirit   を選ぶぜ! ->  Spirit  を初めて使用した経験を元に発表
Boost Spirit  とは? Boost  公式サイトの記述: LL parser framework represents parsers directly as EBNF grammars in inlined C++ 構文解析器を、 C++  内で直接  EBNF  文法を書く事で作れるフレームワーク はぁ?
Boost Spirit  とは? 世間での評判 変態 なことで有名な Boost::Spirit を… http://zo3kirin3.net/?p=82 変態 的と名高い (?) Boost.Spirit  で解析。 http://ja.doukaku.org/comment/6518/ … 同じく 変態 (褒め言葉)と名高い boost::spirit  を使って実装することにした。 http://d.hatena.ne.jp/Hossy/20080407 結論:  Boost Spirit  = 変態
これが  Spirit  の力だ! // #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;   } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が  std::map  に突っ込まれる 型と出力変数定義 入力定義 出力 へ  ん  た  い
高度に発達した C++ は魔法と区別がつかない アーサー? C++ ?クラーク
Boost Spirit  とは? Boost  ライブラリの中でも最高峰の一つ(超私見) Optional, Variant, Fusion, Proto, Phoenix, MPL  等、 他の  Boost  ライブラリをふんだんに使用 C++  でできることのベンチマーク的位置づけ どんなものか知っとくだけでも意味はあるかと Qi, Karma, Lex  で構成 Qi:  構文解析(文字列->データ構造) Karma : 出力(データ構造->文字列) Lex : 字句解析(文字列->トークン列) ← 今回のテーマ
Spirit Qi  入門 Tutorial 嫁
アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive を自作してみる Customization point 蛇足
Boost Spirit  とは? Boost  公式サイト: LL parser framework represents parsers directly as EBNF grammars in inlined C++ 構文解析器を、 C++  内で直接  EBNF  文法を書く 事で作れるフレームワーク
構文解析と  EBNF 構文解析(文字列->データ構造) あるルールに則った文字列を解析 例: 式 10 20 30 40 - * + 0 ( - 4 3 0  0 * ) 2 + 0 1
構文解析と  EBNF EBNF = Extended Backus Normal Form 「あるルール」=文法の表記方法 選択 | 0回以上の繰り返し *、1回以上の繰り返し + 例: 式 <Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* <Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* <Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’
Boost Spirit  の  rule EBNF による式の表現 <Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* <Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* <Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’  C++  の式として有効 Spirit  での式の表現 expr = term >> *(char_(“+-”) >> term); term = factor >> *(char_(“*/”) >> factor); factor = int_ | lit(‘(‘) >> expr >> lit(‘)’);
Boost Spirit  の  rule 構成要素 Parser(基本要素) Directive(修飾) Operator(結合)
Boost Spirit  の  rule Parser(基本要素) 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_
Boost Spirit  の  rule Directive (修飾:Parser の挙動を変える) 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]
Boost Spirit  の  rule Operator (結合) 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
これが  Spirit  の力だ! // #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;   } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が  std::map  に突っ込まれる へ  ん  た  い
Boost Spirit  の  rule *(   lexeme[   *(   graph - char_('=')   )]   >> lit('=')   >> lexeme[   *graph ]) 0 回以上の繰り返し 内部スキップなし 0 回以上の繰り返し =  以外の表示文字 = 内部スキップなし 表示文字の  0  回以上の繰り返し <key>=<value> の繰り返し
で、出力は?
で、出力は? Parser  には「属性」があってその属性型の値を返す int_ -> int / char_ -> char 修飾、結合されたものは? -> Fusion  シーケンス  or STL  コンテナが属性になる char_ >> int_ >> double_  -> tuple<char, int, double> *int_ -> vector<int> int_ >> int_  は? -> どっちでも OK ※ tuple, vector  は代表で  Fusion  シーケンス  /  コンテナなら何でも良い ※ 詳細は「 Quick Reference 」 の「 Compound Attribute Rules 」を参照
で、出力は? pair  はアダプタによって  Fusion  シーケンスと見なせる ( ヘッダの  #include  が必要 ) 構造体も  Fusion  シーケンスと見なせる BOOST_FUSION_ADAPT_STRUCT BOOST_FUSION_DEFINE_STRUCT  で 構造体定義と ADAPT  を一気にできる ※ Fusion  は前回勉強会の  cpp_akira  さんの発表も参照 BOOST_FUSION_DEFINE_STRUCT( (yak)(pdf), indirect_ref, (int, number) (int, generation) ) 構造体  yak::pdf::indirect_ref  が  tuple<int, int>  相当になる
これが  Spirit  の力だ! //  #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;   } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が  std::map  に突っ込まれる へ  ん  た  い
出力先 lexeme  は  skip  の仕方が変わるだけで属性は変化しないので消す lit  は無属性 (unused_type) 、 graph, char_  は char 、 pa – pb  は  pa  の属性 vector<tuple<vector<char>, vector<char> > > or  vector<vector<char> > ※ vector<char>  と  string  は互換 ->これらも互換 *(*(graph - char_('=')) >> lit('=') >> *graph) *(*char >> *char) std::map<std::string, std::string>  std::pair<std::string, std::string>  のコンテナ std::string, std::string  の  Fusion  シーケンスのコンテナ Rule の属性 代入先 *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph])
Spirit.Qi  入門 完 まだ  Spirit  の 変態フェイズは 終了してないぜ!!
アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive  を自作してみる Customization point 蛇足
拡張性 Spirit (の変態性)を支える重要な要素 後から拡張できるような仕掛けがしてある Proto を使っているので自前のコンポーネント(Parser等)を作成できる ->Directive の自作 処理にフックが用意してある ->Customization point
Boost Spirit  の  rule  (再掲) Directive (修飾:Parser の挙動を変える) 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]
Directive  の自作 Parser  の自作は  boost-spirit.com  に記事有り http://bit.ly/ikdvQt 作る物:  delimited (delimiter)[parser] 例:  delimited(std::string(“endstream”))[char_] endstream  という文字列にぶつかるまで  char  を読み出す せっかくなので  char  非限定で作成 std::vector<int> delim(2, -1); delimited(delim)[int_] で  -1 -1  にぶつかるまで  int  を読み出す
Directive  の自作 自作コンポーネントの要素 終端記号の宣言 Parser 本体の定義 属性の型 実際の解析処理 Parser generator の定義(rule -> Parser の変換) 有効化 コンポーネント自身 Semantic action ※ 今回  semantic action  には全く触れませんので  Tutorial  参照
Directive  の自作 終端記号の宣言 namespace mine {   BOOST_SPIRIT_TERMINAL_EX( delimited ) }
Directive  の自作 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) {} ※ Directive  内部の  Parser  の型 delimited(delimiter)[parser]
Directive  の自作 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;  //  デリミタ保持用   }; ※ 属性
Directive  の自作 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> result_type  operator()   (Terminal const& term, Subject const& subject, unused_type) const {   return result_type(subject,  fusion::at_c<0>(term.args) );   } }; }}} 引数の  0  番目要素 Directive  の引数の型:  Delimiter 1 つ delimited (delimiter) [parser] Parser  の コンストラクタ呼び出し
Directive  の自作 有効化 (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_ {};
Directive  の自作 // #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;   } } 出力 Boost.Spirit=extraordinary C++er=... ※ 入力を微妙に変更
ね、简単でしょう?
代替手段 引数 (Inherit attribute) 付きルールを定義 rule<Iterator, std::string(std::string)> delimited; delimited = *(graph_ - _r1) >> omit[_r1]; 使い方   phrase_parse(input.begin(), input.end(),    *(lexeme[ delimited(“=“) ] >> lexeme[*graph]),   space, config); 引数 引数 値を捨てる 引数の型 属性
非実用的入门
Customization point いちいち  Parser  とか  Directive  とか 作ってらんないけど挙動をカスタマイズしたい ->それ、 Spirit  ならできるよ! traits  を特殊化することで挙動を変更
Customization point boost::spirit::traits  以下に用意されている。 SFINAE  用の  Enabler  は省略 is_container<Container> >>  系用 関連:  container_value<Container> etc. handles_container<Component, Attr> >>  系用 transform_attribute<Exposed, Transformed, Domain> rule  系用 assign_to_attribute_from_iterators<Attr, Iterator> 汎用 assign_to_attribute_from_value<Attr, T> 汎用 assign_to_container_from_value<Attr, T> 汎用 push_back_container<Container, Attr> 繰返系用 clear_value<Attr> 繰返系用 etc. create_parser<T> auto_ 用 cf.  http://slashdot.jp/~Yak!/journal/525693
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> を内部で利用
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  読み出し
アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive を自作してみる Customization point 蛇足
Spirit Qi  とうまく付き合うために コンパイル時間が Boost!!!   ->コーヒーでも飲んで優雅に待つといいよ! ※ axpdf--.spi  だとフルビルドに約  10  分 Spirit  関連部分を分離して文法が変わらない限り再コンパイル不要にする Parser  はあくまで  parser  に徹して 構文解析結果に対する処理は別に分けるとか
Spirit Qi  とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB
見えてる範囲 20% 縮小表示 画像補正しないと薄くて文字が 分からないレベル
Spirit Qi  とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB テンプレートのインスタンス化情報がほとんど まずは error で検索
error  で検索 ココ 20% 縮小表示
Spirit Qi  とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB テンプレートのインスタンス化情報がほとんど まずは error で検索 後はどこが真因かインスタンス化情報を遡る…前に 一度エラー箇所を見てみるといいことがあるかも
ケース 1. static_assert エラーメッセージ 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::** )( 何か一杯 ))’ Spirit Qi  とうまく付き合うために
ケース 2.  コメント エラーメッセージ spirit7.cpp:39:  instantiated from here /usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:277: error: no match for call to ‘ 何か一杯’ /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)) Spirit Qi  とうまく付き合うために 277 行目
先生!コンパイル通ったけど思った通りに 動きません! Spirit Qi  とうまく付き合うために   ->プログラムは思った通りに動かない。    書いたとおりに動く。 debug(rule);  を使うと構文解析の様子がトレース できる http://boost- spirit.com /home/articles/doc-addendum/debugging/ 属性に  operator<<  が必要
まとめ Spirit  は変態 真面目に  Spirit  やりたい人は Tutorial  を読みながら一通り実行する boost-spirit.com  の記事を読む 随時  Quick Reference  を参照する
ご静聴ありがとうございました

More Related Content

What's hot (20)

C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会
Akihiko Matuura
?
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
Genya Murakami
?
プログラムの処方笺~健康なコードと病んだコード
プログラムの処方笺~健康なコードと病んだコードプログラムの処方笺~健康なコードと病んだコード
プログラムの処方笺~健康なコードと病んだコード
Shigenori Sagawa
?
boost::shared_ptr tutorial
boost::shared_ptr tutorialboost::shared_ptr tutorial
boost::shared_ptr tutorial
NU_Pan
?
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
Moriharu Ohzu
?
ドキッ!记号だらけの无名関数
ドキッ!记号だらけの无名関数ドキッ!记号だらけの无名関数
ドキッ!记号だらけの无名関数
Shinya Hayakawa
?
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
osamu kimura
?
颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る
Hideyuki Tanaka
?
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
Hiro H.
?
闇魔术を触ってみた
闇魔术を触ってみた闇魔术を触ってみた
闇魔术を触ってみた
Satoshi Sato
?
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
Ryo Suzuki
?
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
Moriharu Ohzu
?
Perl and Email #3 ``Haineko''/Kyoto.pm #5
Perl and Email #3 ``Haineko''/Kyoto.pm #5Perl and Email #3 ``Haineko''/Kyoto.pm #5
Perl and Email #3 ``Haineko''/Kyoto.pm #5
azumakuniyuki ?
?
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
Ransui Iso
?
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
Noboru Irieda
?
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
Yuki Miyatake
?
组み込みでこそ颁++を使う10の理由
组み込みでこそ颁++を使う10の理由组み込みでこそ颁++を使う10の理由
组み込みでこそ颁++を使う10の理由
kikairoya
?
C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会
Akihiko Matuura
?
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
Genya Murakami
?
プログラムの処方笺~健康なコードと病んだコード
プログラムの処方笺~健康なコードと病んだコードプログラムの処方笺~健康なコードと病んだコード
プログラムの処方笺~健康なコードと病んだコード
Shigenori Sagawa
?
boost::shared_ptr tutorial
boost::shared_ptr tutorialboost::shared_ptr tutorial
boost::shared_ptr tutorial
NU_Pan
?
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
Moriharu Ohzu
?
ドキッ!记号だらけの无名関数
ドキッ!记号だらけの无名関数ドキッ!记号だらけの无名関数
ドキッ!记号だらけの无名関数
Shinya Hayakawa
?
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
贰谤濒补苍驳で贰谤濒补驳痴惭上で动く言语の作り方
osamu kimura
?
颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る
Hideyuki Tanaka
?
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」
Hiro H.
?
闇魔术を触ってみた
闇魔术を触ってみた闇魔术を触ってみた
闇魔术を触ってみた
Satoshi Sato
?
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
Ryo Suzuki
?
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
Moriharu Ohzu
?
Perl and Email #3 ``Haineko''/Kyoto.pm #5
Perl and Email #3 ``Haineko''/Kyoto.pm #5Perl and Email #3 ``Haineko''/Kyoto.pm #5
Perl and Email #3 ``Haineko''/Kyoto.pm #5
azumakuniyuki ?
?
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
Ransui Iso
?
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
Noboru Irieda
?
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
叠辞辞蝉迟础蝉颈辞で可読性を求めるのは间违っているだろうか
Yuki Miyatake
?
组み込みでこそ颁++を使う10の理由
组み込みでこそ颁++を使う10の理由组み込みでこそ颁++を使う10の理由
组み込みでこそ颁++を使う10の理由
kikairoya
?

Similar to Impractical Introduction of Boost Spirit Qi [PPT] (20)

Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICL
yak1ex
?
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
yak1ex
?
颁++0虫総復习
颁++0虫総復习颁++0虫総復习
颁++0虫総復习
道化師 堂華
?
わんくま同盟大阪勉强会#61
わんくま同盟大阪勉强会#61わんくま同盟大阪勉强会#61
わんくま同盟大阪勉强会#61
TATSUYA HAYAMIZU
?
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
nyaocat
?
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
mitamex4u
?
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
do_aki
?
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami
?
竞技プログラミングのための颁++入门
竞技プログラミングのための颁++入门竞技プログラミングのための颁++入门
竞技プログラミングのための颁++入门
natrium11321
?
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
伸男 伊藤
?
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
Hiro H.
?
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Hiro H.
?
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
yak1ex
?
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
Yuto Takei
?
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
Hiro H.
?
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
Akira Takahashi
?
Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICL
yak1ex
?
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
yak1ex
?
わんくま同盟大阪勉强会#61
わんくま同盟大阪勉强会#61わんくま同盟大阪勉强会#61
わんくま同盟大阪勉强会#61
TATSUYA HAYAMIZU
?
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
nyaocat
?
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
mitamex4u
?
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
do_aki
?
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami
?
竞技プログラミングのための颁++入门
竞技プログラミングのための颁++入门竞技プログラミングのための颁++入门
竞技プログラミングのための颁++入门
natrium11321
?
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
伸男 伊藤
?
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
Hiro H.
?
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Hiro H.
?
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
yak1ex
?
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
Yuto Takei
?
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
2011.7.3 札幌C++勉強会#2「C++のマクロはどこまで関数をいじれるのか」
Hiro H.
?
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
Akira Takahashi
?

More from yak1ex (7)

Introduction to programming competition [revised][PDF]
Introduction to programming competition [revised][PDF]Introduction to programming competition [revised][PDF]
Introduction to programming competition [revised][PDF]
yak1ex
?
Introduction to programming competition [revised]
Introduction to programming competition [revised]Introduction to programming competition [revised]
Introduction to programming competition [revised]
yak1ex
?
Introduction to programming competition
Introduction to programming competitionIntroduction to programming competition
Introduction to programming competition
yak1ex
?
Brief introduction of Boost.ICL [PDF]
Brief introduction of Boost.ICL [PDF]Brief introduction of Boost.ICL [PDF]
Brief introduction of Boost.ICL [PDF]
yak1ex
?
Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICL
yak1ex
?
GC in C++0x [eng]
GC in C++0x [eng]GC in C++0x [eng]
GC in C++0x [eng]
yak1ex
?
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0x
yak1ex
?
Introduction to programming competition [revised][PDF]
Introduction to programming competition [revised][PDF]Introduction to programming competition [revised][PDF]
Introduction to programming competition [revised][PDF]
yak1ex
?
Introduction to programming competition [revised]
Introduction to programming competition [revised]Introduction to programming competition [revised]
Introduction to programming competition [revised]
yak1ex
?
Introduction to programming competition
Introduction to programming competitionIntroduction to programming competition
Introduction to programming competition
yak1ex
?
Brief introduction of Boost.ICL [PDF]
Brief introduction of Boost.ICL [PDF]Brief introduction of Boost.ICL [PDF]
Brief introduction of Boost.ICL [PDF]
yak1ex
?
Brief introduction of Boost.ICL
Brief introduction of Boost.ICLBrief introduction of Boost.ICL
Brief introduction of Boost.ICL
yak1ex
?
GC in C++0x [eng]
GC in C++0x [eng]GC in C++0x [eng]
GC in C++0x [eng]
yak1ex
?
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0x
yak1ex
?

Recently uploaded (8)

Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
NTT DATA Technology & Innovation
?
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
kota usuha
?
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
Matsushita Laboratory
?
IoT Devices Compliant with JC-STAR Using Linux as a Container OS
IoT Devices Compliant with JC-STAR Using Linux as a Container OSIoT Devices Compliant with JC-STAR Using Linux as a Container OS
IoT Devices Compliant with JC-STAR Using Linux as a Container OS
Tomohiro Saneyoshi
?
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
CRI Japan, Inc.
?
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ssuserfcafd1
?
Matching_Program_for_Quantum_Challenge_Overview.pdf
Matching_Program_for_Quantum_Challenge_Overview.pdfMatching_Program_for_Quantum_Challenge_Overview.pdf
Matching_Program_for_Quantum_Challenge_Overview.pdf
hirokiokuda2
?
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
NTT DATA Technology & Innovation
?
Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
Apache Sparkに対するKubernetesのNUMAノードを意識したリソース割り当ての性能効果 (Open Source Conference ...
NTT DATA Technology & Innovation
?
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
ElasticsearchでSPLADEする [Search Engineering Tech Talk 2025 Winter]
kota usuha
?
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
滨肠丑颈颈搁颈办颈蝉耻办别冲理学疗法士间の知识共有に向けた临床推论テキストの构造化に関する研究.辫诲蹿
Matsushita Laboratory
?
IoT Devices Compliant with JC-STAR Using Linux as a Container OS
IoT Devices Compliant with JC-STAR Using Linux as a Container OSIoT Devices Compliant with JC-STAR Using Linux as a Container OS
IoT Devices Compliant with JC-STAR Using Linux as a Container OS
Tomohiro Saneyoshi
?
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
CRI Japan, Inc.
?
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ドメインモデリング基本编①词全体の流れ2025冲02冲27社内向け开催.辫辫迟虫
ssuserfcafd1
?
Matching_Program_for_Quantum_Challenge_Overview.pdf
Matching_Program_for_Quantum_Challenge_Overview.pdfMatching_Program_for_Quantum_Challenge_Overview.pdf
Matching_Program_for_Quantum_Challenge_Overview.pdf
hirokiokuda2
?
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
NTT DATA Technology & Innovation
?

Impractical Introduction of Boost Spirit Qi [PPT]

  • 1. 非実用的 Boost Spirit Qi 入門 2011/5/14 Boost 勉強会 名古屋 @yak_ex / 新 康孝
  • 2. 自己紹介 氏名: 新 康孝 ( あたらし やすたか ) Twitter ID: yak_ex Web: http://yak3.myhome.cx:8080/junks C++ / Perl が主戦場 現在、仕事でコードに触れていないので 競技プログラミング( TopCoder 、 Codeforces )で 潤い補充 闇の軍団に憧れるただの C++ 好き 初めて Spirit 使った経験を元に発表
  • 3. Spirit との馴れ初め PDF 用 Susie プラグインがライセンスの 関係でずっと公開停止になってる ライセンスの問題がない PDF Susie プラグインを作ろう! 最低限、画像だけ抜いて来られればいいや PDF フォーマットは割とテキストベース 構文解析が必要 ※ プラグインは axpdf--.spi β 版として公開中 せっかくだから俺はこの Spirit を選ぶぜ! -> Spirit を初めて使用した経験を元に発表
  • 4. Boost Spirit とは? Boost 公式サイトの記述: LL parser framework represents parsers directly as EBNF grammars in inlined C++ 構文解析器を、 C++ 内で直接 EBNF 文法を書く事で作れるフレームワーク はぁ?
  • 5. Boost Spirit とは? 世間での評判 変態 なことで有名な Boost::Spirit を… http://zo3kirin3.net/?p=82 変態 的と名高い (?) Boost.Spirit で解析。 http://ja.doukaku.org/comment/6518/ … 同じく 変態 (褒め言葉)と名高い boost::spirit を使って実装することにした。 http://d.hatena.ne.jp/Hossy/20080407 結論: Boost Spirit = 変態
  • 6. これが Spirit の力だ! // #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; } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が std::map に突っ込まれる 型と出力変数定義 入力定義 出力 へ ん た い
  • 8. Boost Spirit とは? Boost ライブラリの中でも最高峰の一つ(超私見) Optional, Variant, Fusion, Proto, Phoenix, MPL 等、 他の Boost ライブラリをふんだんに使用 C++ でできることのベンチマーク的位置づけ どんなものか知っとくだけでも意味はあるかと Qi, Karma, Lex で構成 Qi: 構文解析(文字列->データ構造) Karma : 出力(データ構造->文字列) Lex : 字句解析(文字列->トークン列) ← 今回のテーマ
  • 9. Spirit Qi 入門 Tutorial 嫁
  • 10. アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive を自作してみる Customization point 蛇足
  • 11. Boost Spirit とは? Boost 公式サイト: LL parser framework represents parsers directly as EBNF grammars in inlined C++ 構文解析器を、 C++ 内で直接 EBNF 文法を書く 事で作れるフレームワーク
  • 12. 構文解析と EBNF 構文解析(文字列->データ構造) あるルールに則った文字列を解析 例: 式 10 20 30 40 - * + 0 ( - 4 3 0 0 * ) 2 + 0 1
  • 13. 構文解析と EBNF EBNF = Extended Backus Normal Form 「あるルール」=文法の表記方法 選択 | 0回以上の繰り返し *、1回以上の繰り返し + 例: 式 <Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* <Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* <Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’
  • 14. Boost Spirit の rule EBNF による式の表現 <Expression> ::= <Term> ((‘+’ | ‘-’ ) <Term>)* <Term> ::= <Factor> ((‘*’ | ‘/’ ) <Factor>)* <Factor> ::= <Integer> | ‘(‘ <Expression> ‘)’ C++ の式として有効 Spirit での式の表現 expr = term >> *(char_(“+-”) >> term); term = factor >> *(char_(“*/”) >> factor); factor = int_ | lit(‘(‘) >> expr >> lit(‘)’);
  • 15. Boost Spirit の rule 構成要素 Parser(基本要素) Directive(修飾) Operator(結合)
  • 16. Boost Spirit の rule Parser(基本要素) 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. Boost Spirit の rule Directive (修飾:Parser の挙動を変える) 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. Boost Spirit の rule Operator (結合) 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. これが Spirit の力だ! // #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; } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が std::map に突っ込まれる へ ん た い
  • 20. Boost Spirit の rule *( lexeme[ *( graph - char_('=') )] >> lit('=') >> lexeme[ *graph ]) 0 回以上の繰り返し 内部スキップなし 0 回以上の繰り返し = 以外の表示文字 = 内部スキップなし 表示文字の 0 回以上の繰り返し <key>=<value> の繰り返し
  • 22. で、出力は? Parser には「属性」があってその属性型の値を返す int_ -> int / char_ -> char 修飾、結合されたものは? -> Fusion シーケンス or STL コンテナが属性になる char_ >> int_ >> double_ -> tuple<char, int, double> *int_ -> vector<int> int_ >> int_ は? -> どっちでも OK ※ tuple, vector は代表で Fusion シーケンス / コンテナなら何でも良い ※ 詳細は「 Quick Reference 」 の「 Compound Attribute Rules 」を参照
  • 23. で、出力は? pair はアダプタによって Fusion シーケンスと見なせる ( ヘッダの #include が必要 ) 構造体も Fusion シーケンスと見なせる BOOST_FUSION_ADAPT_STRUCT BOOST_FUSION_DEFINE_STRUCT で 構造体定義と ADAPT を一気にできる ※ Fusion は前回勉強会の cpp_akira さんの発表も参照 BOOST_FUSION_DEFINE_STRUCT( (yak)(pdf), indirect_ref, (int, number) (int, generation) ) 構造体 yak::pdf::indirect_ref が tuple<int, int> 相当になる
  • 24. これが Spirit の力だ! // #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; } } 出力 Boost.Spirit=extraordinary C++er=... <key>=<value> が std::map に突っ込まれる へ ん た い
  • 25. 出力先 lexeme は skip の仕方が変わるだけで属性は変化しないので消す lit は無属性 (unused_type) 、 graph, char_ は char 、 pa – pb は pa の属性 vector<tuple<vector<char>, vector<char> > > or vector<vector<char> > ※ vector<char> と string は互換 ->これらも互換 *(*(graph - char_('=')) >> lit('=') >> *graph) *(*char >> *char) std::map<std::string, std::string> std::pair<std::string, std::string> のコンテナ std::string, std::string の Fusion シーケンスのコンテナ Rule の属性 代入先 *(lexeme[*(graph - char_('='))] >> lit('=') >> lexeme[*graph])
  • 26. Spirit.Qi 入門 完 まだ Spirit の 変態フェイズは 終了してないぜ!!
  • 27. アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive を自作してみる Customization point 蛇足
  • 28. 拡張性 Spirit (の変態性)を支える重要な要素 後から拡張できるような仕掛けがしてある Proto を使っているので自前のコンポーネント(Parser等)を作成できる ->Directive の自作 処理にフックが用意してある ->Customization point
  • 29. Boost Spirit の rule (再掲) Directive (修飾:Parser の挙動を変える) 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. Directive の自作 Parser の自作は boost-spirit.com に記事有り http://bit.ly/ikdvQt 作る物: delimited (delimiter)[parser] 例: delimited(std::string(“endstream”))[char_] endstream という文字列にぶつかるまで char を読み出す せっかくなので char 非限定で作成 std::vector<int> delim(2, -1); delimited(delim)[int_] で -1 -1 にぶつかるまで int を読み出す
  • 31. Directive の自作 自作コンポーネントの要素 終端記号の宣言 Parser 本体の定義 属性の型 実際の解析処理 Parser generator の定義(rule -> Parser の変換) 有効化 コンポーネント自身 Semantic action ※ 今回 semantic action には全く触れませんので Tutorial 参照
  • 32. Directive の自作 終端記号の宣言 namespace mine { BOOST_SPIRIT_TERMINAL_EX( delimited ) }
  • 33. Directive の自作 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) {} ※ Directive 内部の Parser の型 delimited(delimiter)[parser]
  • 34. Directive の自作 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; // デリミタ保持用 }; ※ 属性
  • 35. Directive の自作 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> result_type operator() (Terminal const& term, Subject const& subject, unused_type) const { return result_type(subject, fusion::at_c<0>(term.args) ); } }; }}} 引数の 0 番目要素 Directive の引数の型: Delimiter 1 つ delimited (delimiter) [parser] Parser の コンストラクタ呼び出し
  • 36. Directive の自作 有効化 (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_ {};
  • 37. Directive の自作 // #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; } } 出力 Boost.Spirit=extraordinary C++er=... ※ 入力を微妙に変更
  • 39. 代替手段 引数 (Inherit attribute) 付きルールを定義 rule<Iterator, std::string(std::string)> delimited; delimited = *(graph_ - _r1) >> omit[_r1]; 使い方 phrase_parse(input.begin(), input.end(), *(lexeme[ delimited(“=“) ] >> lexeme[*graph]), space, config); 引数 引数 値を捨てる 引数の型 属性
  • 41. Customization point いちいち Parser とか Directive とか 作ってらんないけど挙動をカスタマイズしたい ->それ、 Spirit ならできるよ! traits を特殊化することで挙動を変更
  • 42. Customization point boost::spirit::traits 以下に用意されている。 SFINAE 用の Enabler は省略 is_container<Container> >> 系用 関連: container_value<Container> etc. handles_container<Component, Attr> >> 系用 transform_attribute<Exposed, Transformed, Domain> rule 系用 assign_to_attribute_from_iterators<Attr, Iterator> 汎用 assign_to_attribute_from_value<Attr, T> 汎用 assign_to_container_from_value<Attr, T> 汎用 push_back_container<Container, Attr> 繰返系用 clear_value<Attr> 繰返系用 etc. create_parser<T> auto_ 用 cf. http://slashdot.jp/~Yak!/journal/525693
  • 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. 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. アジェンダ 概要紹介 限定された使い方のみ 拡張性 Directive を自作してみる Customization point 蛇足
  • 46. Spirit Qi とうまく付き合うために コンパイル時間が Boost!!!   ->コーヒーでも飲んで優雅に待つといいよ! ※ axpdf--.spi だとフルビルドに約 10 分 Spirit 関連部分を分離して文法が変わらない限り再コンパイル不要にする Parser はあくまで parser に徹して 構文解析結果に対する処理は別に分けるとか
  • 47. Spirit Qi とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB
  • 48. 見えてる範囲 20% 縮小表示 画像補正しないと薄くて文字が 分からないレベル
  • 49. Spirit Qi とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB テンプレートのインスタンス化情報がほとんど まずは error で検索
  • 50. error で検索 ココ 20% 縮小表示
  • 51. Spirit Qi とうまく付き合うために エラーメッセージ量が Boost!!! ->例: 3.3MB テンプレートのインスタンス化情報がほとんど まずは error で検索 後はどこが真因かインスタンス化情報を遡る…前に 一度エラー箇所を見てみるといいことがあるかも
  • 52. ケース 1. static_assert エラーメッセージ 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::** )( 何か一杯 ))’ Spirit Qi とうまく付き合うために
  • 53. ケース 2. コメント エラーメッセージ spirit7.cpp:39: instantiated from here /usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:277: error: no match for call to ‘ 何か一杯’ /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)) Spirit Qi とうまく付き合うために 277 行目
  • 54. 先生!コンパイル通ったけど思った通りに 動きません! Spirit Qi とうまく付き合うために   ->プログラムは思った通りに動かない。   書いたとおりに動く。 debug(rule); を使うと構文解析の様子がトレース できる http://boost- spirit.com /home/articles/doc-addendum/debugging/ 属性に operator<< が必要
  • 55. まとめ Spirit は変態 真面目に Spirit やりたい人は Tutorial を読みながら一通り実行する boost-spirit.com の記事を読む 随時 Quick Reference を参照する