2016-09-26 63 views
1

我创建了一个编译器(用于酷语言)作为个人项目,并且在设计符号表时遇到了麻烦。对于上下文,我使用类的层次结构作为我的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*等以实际使用它。

如何设计我的符号表以避免为向下转换的需要的呢?

+2

我不会说在这里downcasting一定是个大问题。你可以从上下文知道目标类型。当然,因为Cool源代码包含错误,所以downcast仍然会失败,但在这种情况下,您的'dynamic_cast'失败,并且您将其作为直接错误输出,例如'期望一个班,但是“Foo”命名一个功能'。 – MSalters

+0

也许:摆脱基本的'NodeAst'并使所有'accept'函数成为非虚拟模板。相比之下,您可能会让访问者在每种集合类型上运行不同。 –

+0

@DieterLücking:通常几乎不需要删除基类;您仍然可以通过继承实例化碰巧相关的类。 – MSalters

回答

1

我不知道你要实现的编程语言,但我不认为这是真的可能是你能避免动态蒙上完全。例如,在f(1),f可能是一个函数或变量,如果您的语言有lambda表达式。你需要在符号表中查找它。

如果你能absoluteley排除这种可能性,理论上你可以创建为每种类型的单独的符号表。但请记住,如果需要检测名称冲突,显然会更难找到名称冲突,并且可能意味着您的编程语言稍后难以扩展。我不会推荐这个解决方案。

个人而言,我只是想让to_class()to_var()is_class()is_var()等方法添加到您的NodeAST类,从而使动态转换封装,而不是围绕整个代码库蔓延。你也可以创建一个类为您的符号表,这样就可以与get_class()访问元素,get_var()

如果您担心在C++中RTTI的运行成本,你可以看看其他的解决方案编译器使用。对于LLVM是这里描述:http://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html

1

我已经使用访问者模式非常成功,在过去访问指针的容器有一个共同的基础。在一个实现中,我比dynamic_cast <>实现经历了大约40%的加速,这对于我正在编写的数据库抽象层非常重要。

有一个Dispatcher类被访问这里的答案之一多一点的解释.... Right design pattern to deal with polymorphic collections of objects

Visitor Pattern的维基百科页面也给基指针的集合的一个漂亮的短C++的例子。

你已经显示了你的问题了“的Visitable”类的源代码。我们需要查看您的“访问者”的实施情况,以了解您为什么需要dynamic_cast <>。这不应该是必要的。使用正确的visit()函数应该通过函数参数重载来选择。

干杯

+0

没有必要在访问者模式的非模板实现中向下转发(如果要使用模板调查通用访问者实现,请搜索Loki库)。不确定接受的答案是否正确,但没有评论的声誉! –

+0

为了插入符号表,我使用访问者模式遍历AST并插入命名值。这很好。问题出在我的TypeCheckVisitor类中。再次,我使用访问者模式遍历并为每个AST节点执行分析。在分析过程中,我需要查询符号表。例如,我需要在BinaryOperator节点中获取LHS和RHS的类型。我需要这些类型在我正在使用的typeCheckBinaryOperator函数中(作为访问者模式的结果)。我没有看到如何做到这一点,而不是先将LHS和RHS向下变为变量。 – ryan