Rationale

仮想関数:静的な C++ から動的な C++ へ

ルールは静的な C++ と動的な C++ との間の境界をまたいでいる。 事実上、ルールは(テンプレートを用いた)コンパイル時ポリモーフィズムを(仮想関数を用いた)実行時ポリモーフィズムに変換する。 C++ は、 代入の右辺(rhs)にある任意の複雑な式から推定した型の変数を自動的に宣言することができないので、これが必要になる。 基本的には、例えば次のようなことを欲しているわけだが:

    T rule = an_arbitrarily_complex_expression;

代入式の右辺(rhs)の結果の型を知ったり、対処することなしにやりたいのである。 このほかに、不明な型を前方宣言する(forward declare)機能も必要である:

    T rule;
    ...
    rule = a | b;

これらの制限からこのようなルールの実装になった。 その代償として、ルールの呼び出しごとに仮想関数呼び出しのオーバーヘッドが掛かってしまう。

多重宣言

BNF の変種の中には rule の多重宣言を許すものがある。 それらの宣言は選択として扱われる。例えば:

   r = a;    
   r = b;

これは以下と等価である:

   r = a | b;

Spirit v1.3 はこの振る舞いを許していた。しかし、現在のバージョンの Spirit はもはやこれを許していない。 経験から言って、この振る舞いは望まざる結果をもたらすからである(例えば、コンテナに保持されるルールが許されない)。 Spirit の現在のリリースでは、あるルールへの二つ目の代入は単にそれを再定義する。古い定義は破壊される。これは C++ の動作により厳密に従っており、またユーザがルールに望む振る舞いにより合致している。

シーケンスの構文

a, b のようなカンマ演算子は、構文的には、よりよい対案に見える。 しかし、問題はその優先順位である。それは C/C++ では最も低い優先順位であり、本質的に使えないものになってしまっている。

Bjarne Stroustrup は彼の記事 "Generalizing Overloading for C++2000"の中で空白のオーバーロードについて語っている。 そのような機能があれば (E)BNF でやるのとまったく同じようにパーサオブジェクトを並べることが可能になる(例えば a >> b | c ではなく a b | c )。 残念ながら、その記事の日付は 1998 年 4 月 1 日となっている。やれやれ。

前方向イテレータ

一般に、スキャナは少なくとも標準に準拠した前方向イテレータであることが望まれる。 バックトラックする際にはイテレータを保存して後で復元する必要があるため、前方向イテレータが必要とされる。 一般的に言えば、 Spirit はバックトラッキングパーサである。 これが意味することは、ある時点で、パーサが前の位置にバックトラックできるように イテレータポジションを保存しなければならない、ということである。 従って、バックトラックが機能するために、フレームワークは少なくとも前方向イテレータを要求するのである。

パーサの中にはより限定されたイテレータ(双方向あるいはランダムアクセスさえ)を要求するものもあり得る。 恐らく近い将来、決定性のパーサがフレームワークに加えられれば、それらはバックトラック無しで動作し、トークン一つだけ先読みすればよく、従って入力イテレータのみを要求するだろう。

サブルールはなぜ重要か?

仮想関数に依存しないサブルールは、より積極的なメタプログラミングの機会に恵まれている。 仮想関数はメタプログラマの地獄だ。 仮想関数の間接呼び出しによってプログラムの速度を低下させるだけでなく、 どのメタプログラムも通り抜けることのできない見えざる壁でもある。 仮想関数呼び出しを超えると全てのメタ情報をご破算にする。 さらに悪いことに、仮想関数はテンプレート化できない。 つまり、その引数は実際の型に結びつけられてしまうのである。 多くの問題がこの制限から生じる。

Spirit は現在のところ非決定性再帰下降パーサと分類されているが、 トップダウン再帰下降以外の他の構文解析技法を適用することができることを Doug Gregor が初めて指摘した。 例えば、非決定性再帰下降ではなく、決定性 LL(1) および LR(1) は理論的には同じ式テンプレートフロントエンドを用いて実装することができる。 Spirit のルールは RHS parser expression を不明確な抽象パーサ型にエンコードするのに仮想関数を用いている。 それはその目的にはよく役立っているが、ルールの仮想関数はより進んだメタプログラミングの障害物である。サブルールは仮想関数から解放されている。



このドキュメントの対象: Boost Version 1.30.0
最新版ドキュメント(英語)