私は個人的なプロジェクトとして(クールな言語用の)コンパイラを作成していますが、シンボルテーブルを設計する際に問題があります。コンテキストの場合、私はASTとしてクラスの階層を使用しています。ここではASTの小さな抜粋です:おもちゃのコンパイラのシンボルテーブル
現在class NodeAST {
public:
virtual void accept(Visitor&) = 0;
};
class ProgramAST : public NodeAST {
private:
const std::vector<ClassPtr> vClasses;
public:
ProgramAST(std::vector<ClassPtr> vClasses);
auto class_cbegin() const {
return std::cbegin(vClasses);
}
auto class_cend() const {
return std::cend(vClasses);
}
virtual void accept(Visitor& v) override;
};
class ClassAST : public NodeAST {
private:
const std::string name;
const std::vector<FeaturePtr> vFeatures;
public:
ClassAST(std::string name, std::vector<FeaturePtr> vFeatures);
auto getName() const {
return name;
}
auto feature_cbegin() const {
return std::cbegin(vFeatures);
}
auto feature_cend() const {
return std::cend(vFeatures);
}
virtual void accept(Visitor& v) override;
};
、私のシンボルテーブルの中心に、以下のように定義されたマップである。
std::unordered_map<std::string, NodeAST*> table
それはで対応するノードに宣言の名前をマップAST。このようにして、たとえば、私がASTノードで設定した型を使って、ゆるい識別子の型を記入することができます。
ただし、ノードのシンボルテーブルにクエリを実行すると、NodeAST*
が返されるという問題があります。実際に使用するにはClassAST*
、MethodAST*
、VarDecAST*
などにダウンキャストする必要があります。
ダウンキャストの必要性を回避する方法でシンボルテーブルを設計するにはどうすればよいですか?
私はダウンキャスティングが必然的に大きな問題であるとは言いません。コンテキストからターゲットタイプを知ることができます。クールなソースコードにはエラーが含まれているのでダウンキャストは失敗する可能性がありますが、その場合は 'dynamic_cast'が失敗し、直接エラーとして出力します。 'クラスを期待しましたが、" Foo "は関数の名前を付けました。 – MSalters
多分:ベース 'NodeAst'を取り除き、すべての' accept'関数を非仮想テンプレートにしてください。より多くの訪問者がそれぞれのコレクションタイプで異なる動作をする可能性があります。 –
@DieterLücking:通常、基本クラスを削除する必要はほとんどありません。継承によって関連づけられたクラスでテンプレートをインスタンス化することはできます。 – MSalters