Grammatica で日本語を扱う方法

文法ファイルから,字句解析および構文解析を生成するジェネレータには,JavaC#に対応したLLのパーザジェネレータ Grammaticaがお気に入りです.文法が直感的に書けますし,パーザ実行時のエラー検出の振る舞いなど,とても使いやすいです.

さてGrammatica ver 1.4で日本語を扱おうとして,ちょっとはまったのでメモ.

結論は,自動生成された字句解析クラスのコードにあるパターンを直接編集することです.例えば日本語のある文字範囲を受理するトークンを書くには,自動生成された字句解析クラス(ファイル名 xxxTokenizer.cs)のメソッドCreatePatterns()の中で,トークンの正規表現パターンを追加しているところで,例えば[(文字A)-(文字B)]のような正規表現を書きます.(文字A)および(文字B)は,受理したいUnicode文字コード範囲の最初および最後の文字です.

これは, Grammaticaが独自に実装している正規表現エンジンの振る舞いが原因です.C#Unicodeの文字範囲を指定する正規表現には,[\uxaaa-\uxbbb] (xaaa,xbbb はUnicode文字コードを16進表記で表したもの)をよく使います.Grammaticaの正規表現解析コードは,\uxxxxのエスケープシーケンスは処理するのですが,エスケープシーケンスの処理ルーチンはそこで終わるために続く範囲指定の"-"を処理できません.従って [\uxxxx-\uxxxx]と範囲指定を意図して記述しても,Grammaticaのエンジンは,文字コードが\uxxxの文字"および文字"-"および文字コードが"\uxxxx"の文字,のいずれかの文字と解析します.

自動生成されたコードを編集するのは嫌なので,文法にUnicodeで文字を書いてみたのですが,こうするとコード生成プログラムが文法ファイルを正しく読めないみたいでした.

そこで,自動生成された字句解析クラスの正規表現に直接記述したUnicodeは受理できるので,先ほどのようにエスケープシーケンスではなくて,文字コードに対応する文字を直接書くわけです.

コードをちゃんと書いてパッチを送ればいいのですが,構文自体は英数文字で指定するため,日本語の範囲指定が必要になるトークンは1つだけですむために,置換箇所は1箇所だけになるため,手で編集しても手間ではないので,とりあえずパス.