「Wiki処理系を作る前に知るべきこと/考えるべきこと」において、WikiCreole構文の問題点を指摘して、「Wikiの要素を分類してみる」では、Wiki構文の厳密な形式的記述の準備を始めた、と言いました。
で、まー、Wiki構文の記述や解析が厄介で泥臭くなってしまう事情と理由が少し見えてきました。
- Wiki構文の区切り記号は激しく文脈依存である。有限状態機械の処理モデルでは無理があり、無限状態機械のモデルが必要になる。
- しかし、文脈依存性と無限状態は、それほどタチが悪いわけではない。割ときれいな定式化が可能である。
- 開始記号の認識に先読みが必要になるが、これも特に問題というほどではない。
ここまでは要するに「特に悪いことはないよ」って話です。ところが、実際には悪いことがあります -- もうやんなっちゃってウンザリするのはどこかというと、終了記号の認識なんです。Wiki文書には、段落や箇条書きのようなブロック要素、あるいは強調のようなインライン要素があり、それらの要素の終了位置を識別しなくてはなりません。これが、記述も処理もめんどくさい、汚い。
このような事情が鮮明になってきたのは、“スタックで状態を表現する抽象機械”をモデルとするメタ言語による構文記述を始めたからです。今、時間がないので、説明なしに例を載せます。ごく簡単なWiki構文です。実は、以下の記述では終了記号の認識をちゃんと考慮してません。だからきれいに書けています。もっと実用的レベルで終了を意識するとどうなるか? 考えてみてください。続きは明日以降に書きます。
module verySimpleWiki-1;
/*
* グローバルな特殊ルール
*/// テキストの先頭でtoplevelに入る
$BOT ==> enter(toplevel);/*
* トップレベル文脈
*/
context toplevel = {// 空行は捨てる
blankLine ::= BOL (SP|TAB)* EOL
==> discard;// レベル1見出しの検出
startH1 ::= BOL (SP|TAB)* '=' / ^'='
==> enter(h1);// レベル2見出しの検出
startH2 ::= BOL (SP|TAB)* '==' / ^'='
==> enter(h2);// 空行でもなく、見出しでもない
// そのときは段落
startP ::= EMPTY
==> enter(p);};
/*
* 見出し h1, h2
*/// h1, h2 共通だからグローバルに定義しておく
endHeading ::= '='* (SP|TAB)* EOL;context h1 = {
endHeading ==> leave;
};context h2 = {
endHeading ==> leave;
};
/*
* 段落
*/context p = {
// 子要素の検出
startStrong ::= '**'
==> enter(strong);// 終了の検出
endP ::= BOL (SP|TAB)* EOL;
==> leava;
};/*
* 重要語句
*/context strong = {
// 終了の検出
endStrong ::= '**' ==> leave;
};