玩具编译器符号表
Toy Compiler Symbol Table
我正在创建一个编译器(用于Cool语言)作为个人项目,我在设计符号表时遇到了麻烦。出于上下文的考虑,我使用了一个类的层次结构作为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;
};
目前,我的符号表的核心是一个map,定义如下:
std::unordered_map<std::string, NodeAST*> table
它将声明的名称映射到AST中相应的节点,这样,例如,我可以使用我在AST节点中设置的类型填充松散标识符的类型。
然而,问题是,当我查询符号表中的节点时,我得到的是一个NodeAST*
。因此,我必须将其降为ClassAST*
, MethodAST*
或VarDecAST*
等来实际使用它。我如何设计我的符号表,以避免需要向下转换?
我不知道您正在实现的编程语言,但我认为您确实不可能完全避免动态强制转换。例如,在f(1)
中,如果您的语言有lambdas, f
可以是函数或变量。你需要通过在符号表中查找它来找出它。
如果可以绝对排除这种可能性,理论上可以为每种类型创建单独的符号表。但是请记住,如果您需要检测名称冲突,那么这显然会使查找名称冲突变得更加困难,并且可能意味着您的编程语言以后更难以扩展。我不推荐这个解决方案。
就我个人而言,我只会添加像to_class()
, to_var()
, is_class()
, is_var()
等方法到你的NodeAST
类,这样动态强制转换被封装,而不是在整个代码库中传播。你也可以为你的符号表创建一个类,这样你就可以访问get_class()
, get_var()
等元素。
如果你担心c++中RTTI的运行时成本,你可以看看其他编译器正在使用的解决方案。对于LLVM,如下所示:http://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html
我在过去非常成功地使用访问者模式访问具有公共基的指针容器。在一个实现中,我经历了比dynamic_cast<>实现大约40%的加速,这在我正在编写的数据库抽象层中很重要。
在这里的一个答案中有更多的解释....处理对象的多态集合的正确设计模式
关于访问者模式的Wikipedia页面也给出了一个很好的简短的c++示例,该示例展示了Dispatcher类访问的基指针集合。
你已经在你的问题中显示了一个"可访问"类的源代码。我们需要查看"访问者"的实现,以了解为什么需要dynamic_cast<>。这应该是不必要的。应该通过函数参数重载来选择要使用的正确的visit()函数。
欢呼
- 是否有任何 2 补充平台/编译器,其中有符号移位不做通常的事情?
- C++ 如何禁用具有不同符号变量比较的特定行的编译器警告?
- Android Cmake编译器正在生成带有额外前缀和符号后缀的.out文件
- 如何确定'malloc'符号是来自源还是来自编译器?
- Clang编译器/链接器找不到x86_64架构的符号NSMenuItem
- 编译器链接器外部符号mhook_sethook
- 来自 clang/llvm 编译器的重复符号错误
- C++编译器或预处理器是否可以将符号转换为大写
- 什么是 ?和 @ 符号演示此编译器错误?- Visual Studio 2013 Compiler.
- 编译器错误:从int*到无符号int*的转换无效[-fpermission]
- 现代编译器是否优化了for循环中使用的无符号int
- boost::bind 似乎使用不同的编译器生成不同的符号
- Visual C++编译器为不明确的符号提供了错误的行引用
- types.h中的内容——编译器在哪里定义int、带符号int和其他值的宽度
- C++ 在 Win DLL 到 Linux SO 转换中将 LPBYTE 更改为无符号字符*后编译器错误
- 如何防止编译器/链接器去除特定符号
- C++编译器 - 生成的符号类型
- 在 Scala 2.9.3 编译器的擦除阶段之后获取具体类型的符号
- 有符号整数溢出为负数:这是一个编译器错误,还是我误解了优化
- 编译器构造:处理对无序符号的引用