私はいくつかの小さな言語でいくつかの処理を行うためにQiとKarmaを使用してきました。ほとんどの文法はかなり小さい(20-40ルール)。私はautorulesをほとんど排他的に使用することができたので、私の解析木は完全にバリアント、構造体、およびstd :: vectorsで構成されています。
1))、何か(チー)を解析
2)構文解析ツリー(訪問者にマイナーな操作を行い、
3)出力の何か(カルマ):Boost :: Spirit :: Qi autorules - ASTデータ構造の繰り返しコピーを避ける
このセットアップは、一般的なケースのために素晴らしい作品。
しかし、大きなサブツリーを動かすなど、構文木に複雑な構造変更を加えたいと思ったらどうなるでしょうか。 ...
autorulesを使用して、S-exprのスタイルの論理式のための文法...
// Inside grammar class; rule names match struct names...
pexpr %= pand | por | var | bconst;
pand %= lit("(and ") >> (pexpr % lit(" ")) >> ")";
por %= lit("(or ") >> (pexpr % lit(" ")) >> ")";
pnot %= lit("(not ") >> pexpr >> ")";
...このようになりますツリー表現を解析するためにつながる次のおもちゃの例を考えてみましょう
pand
/... \
por por
/\ /\
var var var var
(T:
struct var {
std::string name;
};
struct bconst {
bool val;
};
struct pand;
struct por;
struct pnot;
typedef boost::variant<bconst,
var,
boost::recursive_wrapper<pand>,
boost::recursive_wrapper<por>,
boost::recursive_wrapper<pnot> > pexpr;
struct pand {
std::vector<pexpr> operands;
};
struct por {
std::vector<pexpr> operands;
};
struct pnot {
pexpr victim;
};
// Many Fusion Macros here
私はこのようになります解析木を持っていると仮定彼は「pand
のために類似した形状のより多くの子どもたち。」手段を省略記号)
を今、最終的な結果があるように私は、por
各ノードを否定したいと:
pand
/... \
pnot pnot
| |
por por
/\ /\
var var var var
直接的なアプローチだろうそれぞれpor
サブツリーに対して:
- 作成pnot
ノード
(構成はpor
)
pand
ノード
(pnot
ノードとそのpor
サブツリーをコピー)に適切なベクトルスロットを再割り当てします。
また、別のベクターを作成してから、pand
ベクターの卸売りを交換(交換)して、2回目のコピーを削除することができました。
このすべては、既存のノードをコピーせずにpnot
ノードを挿入できるようにするポインタベースのツリー表現に比べて面倒なようです。私の質問:
オートホール準拠のデータ構造でコピーが多いツリー操作を避ける方法はありますか?私は弾丸を噛んで、ポインタベースのAST(例えば、http://boost-spirit.com/home/2010/03/11/s-expressions-and-variants/)を構築するために非オートルールを使用するだけですか?
あなたの洞察をお寄せいただきありがとうございます。私は変種の実装にあまり注意を払っていなかった。 - 既存の2つのノードの間にノードを挿入すると、一定数のコピー操作が発生します(挿入の下にあるサブツリーのサイズとともに増加しません)。 - ほとんどのコピーはベクトルサイズ変更によって発生します これは、定型的な意味操作を必要とせずに、プール割り当てのポインタベースのASTノードに対してディレクタのサポートを持つことがうまくいくかもしれません。その設定の1つの素晴らしい特性は、安価な一意のハッシュとしてノードアドレスを使用できることです。 – phooji