valgrind の一部である callgrind ツールの出力用の Boost.Spirit パーサーを作成しようとして行き詰まりました。Callgrind はドメイン固有の組み込みプログラミング言語 (DSEL) を出力します。これを使用すると、合成カウンターのカスタム式など、あらゆる種類の優れた機能を実行できますが、解析するのは簡単ではありません。
サンプルの callgrind 出力をhttps://gist.github.com/ned14/5452719#file-sample-callgrind-outputに配置しました。https://gist.github.com/ned14/5452719#file-callgrindparser-hppおよびhttps://gist.github.com/ned14/5452719で、Boost.Spirit lexer およびパーサーに現在の最善の試みを行いました。 #file-callgrindparser-cxx . レクサー部分は簡単です。タグ値、空白以外のテキスト、コメント、行末、整数、16 進数、浮動小数点数、および演算子をトークン化します (サンプル コードの句読点は無視してください。これらは使用されていません)。空白はスキップされます。
ここまでは順調ですね。問題は、トークン化された入力ストリームの解析です。私はまだ主要なスタンザを試みていませんが、ファイル内の任意の場所で発生する可能性のあるタグ値を解析しようとしています。タグの値は次のようになります。
tagtext: unknown series of tokens<eol>
自由形式のテキストでもかまいません。
desc: I1 cache: 32768 B, 64 B, 8-way associative, 157 picosec hit latency
この状況では、一連のトークンを文字列、つまり iterator_range に変換して抽出する必要があります。
ただし、式の場合もあります。
event: EPpsec = 316 Ir + 1120 I1mr + 1120 D1mr + 1120 D1mw + 1362 ILmr + 1362 DLmr + 1362 DLmw
これは、これから、イベント EPpsec は、I1mr に 1120 を掛けたものに Ir を掛けた 316 を足したものとして合成されることを意味します。
ここで言いたいのは、タグと値のペアを任意のトークンのセットとして蓄積し、後処理して後で変換する必要があるということです。
そのために、Boost.Spirit の utree() クラスはまさに私が求めていたものであり、それがサンプル コードで使用されています。しかし、VS2012 で 11 月の CTP コンパイラを可変個引数テンプレートとともに使用すると、現在、次のコンパイル エラーが発生しています。
1>C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(56): error C2440: 'static_cast' : cannot convert from 'boost::spirit::detail::list::node_iterator<const boost::spirit::utree>' to 'base_iterator_type'
1> No constructor could take the source type, or constructor overload resolution was ambiguous
1> C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(186) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const Range>(ForwardRange &)' being compiled
1> with
1> [
1> IteratorT=base_iterator_type
1> , Range=boost::spirit::utree
1> , ForwardRange=boost::spirit::utree
1> ]
...これは、前方反復子の性質のためのistreambuf_iteratorのBoost.Spirit multi_pass<>ラップである私のbase_iterator_typeが、Boost.Spiritのutree()実装によって何らかの形で理解されていないことを示唆しています。つまり、これが私の悪いコードなのか、それとも悪い Boost.Spirit コードなのかはわかりません。
過去の Stackoverflow ヘルプのおかげで、トークン化されていない純粋な文法を書くことができましたが、それはもろいでしょう。適切な解決策は、トークン化して、かなり任意の入力が可能な自由形式の文法を使用することです。Boost.Spirit の Lex と Grammar を実際の例で連携させてこれを達成した例は、おもちゃの例ではなく、残念ながら非常に少ないです。したがって、どんな助けでも大歓迎です。
ニール