Boost::SpiritでCMS計画 (2)
WikiライクなCMSをBoost::Spiritという変態的なC++ライブラリを用いてつくろうという企画の『Boost::SpiritでCMS計画』。ある程度形ができてきたので、進捗状況の報告といきたいと思います。
記法をある程度定めてそれに対するアクションを定めました。記法はほぼWiki+RDです。文法の紹介を簡単にすると
- Wikiエリア(処理される部分)は=beginで始まって=endで終わる
- インライン要素は
- 下線 __ (下線を引きたい言葉) __
- 打ち消し線 == (打ち消したい言葉) ==
- 強調 '' 強調したい言葉 ''
- リンク [[ リンク先 (空白 エイリアス) ]]
- ブロック要素は
- 番号付リスト +で段階数指定 最後に&をつけることで継続
- 番号なしリスト -で段階数指定 最後に&をつけることで継続
- 見出し !で段階数指定
- 自動改行挿入 元の文改行で<br />が挿入される、直後がブロック要素の際は挿入されない
ソースを公開します。Spiritを使う方の参考になれば幸いです。
細かいソースは続きをどうぞ。
※その後、パーサとレンダラーを分離しました。
それにしてもSpiritは面白いです。さらに、構文木を生成せずにstackを使って1パスで処理するように実装したため、コードがなかなか楽しいことになっていますが。そんなこんなですが、思いついたアイデアをぼちぼち紹介していこうと思います。
今回はダイナミックパースの利用についてです。単純にパーサを書くとインライン要素が入れ子になってしまうことがあります。例えば強調の中に打ち消しがネストして、さらに打ち消しの中に強調がネストしたりするのは、実装としては簡単ですが、文法的におかしいので是非回避したいところです。そんなときはセマンティックアクションを使って動的(ダイナミック)に抑制するといいでしょう。コードをあげてみます。
rule<ScannerT> &_r1, &_r2;
ChangeRule(rule<ScannerT> &r1, rule<ScannerT> &r2) : _r1(r1), _r2(r2){}
void operator()(IteratorT first, IteratorT last) const {
_r1 = _r2;
}
};
rule<ScannerT> inline1_p, inline2_p;
rule<ScannerT> nest_inline1_p, nest_inline2_p, nest_off_p;
inline1_p = start1_p[ ChangeRule(nest_inline1_p, nest_off_p) ]
>> (nest_inline2_p
>> close1_p
| eps_p)[ ChangeRule(nest_inline1_p, inline1_p) ];
inline2_p = start2_p[ ChangeRule(nest_inline2_p, nest_off_p) ]
>> (nest_inline1_p
>> close2_p
| eps_p)[ ChangeRule(nest_inline2_p, inline2_p) ];
nest_off_p = nothing_p;
nest_inline1_p = inline1_p;
nest_inline2_p = inline2_p;
コメント
コメントする
- 匿名でのコメントは受け付けておりません。
- お名前(ハンドル名可)とメールアドレスは必ず入力してください。
- メールアドレスを表示されたくないときはURLも必ず記入してください。
- コメント欄でHTMLタグは使用できません。
- コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
- コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。
- 投稿ボタンを押してエラーがでなければ、投稿は成功しています。反映されるまでには少し時間がかかります。