我创建了一个编译器(用于酷语言)作为个人项目,并且在设计符号表时遇到了麻烦。对于上下文,我使用类的层次结构作为我的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*
等以实际使用它。
如何设计我的符号表以避免为向下转换的需要的呢?
我不会说在这里downcasting一定是个大问题。你可以从上下文知道目标类型。当然,因为Cool源代码包含错误,所以downcast仍然会失败,但在这种情况下,您的'dynamic_cast'失败,并且您将其作为直接错误输出,例如'期望一个班,但是“Foo”命名一个功能'。 – MSalters
也许:摆脱基本的'NodeAst'并使所有'accept'函数成为非虚拟模板。相比之下,您可能会让访问者在每种集合类型上运行不同。 –
@DieterLücking:通常几乎不需要删除基类;您仍然可以通过继承实例化碰巧相关的类。 – MSalters