已关闭。此问题为opinion-based。当前不接受答案。
**想要改进此问题吗?**请更新此问题,以便editing this post可以用事实和引文来回答。
昨天关门了。
Improve this question
作为一个充满激情的项目,我写编译器已经有一段时间了。目前,编译器完全是用C编写的。我使用访问者模式来进行类型检查、代码生成、调试打印等。随着时间的推移,我意识到,我不需要这样一个复杂的系统来表示各种AST节点。每当我想添加另一个AST节点时,它需要添加大量的样板代码和方法来“访问”该节点。
我一直在考虑用C语言重写编译器的前端,但在后端仍然使用C LLVM-IR API来简化操作。我认为OOP可能会给AST节点的表示方式增加一些不必要的复杂性,所以我在C语言中使用了Facade模式:
typedef enum {
AST_NUM,
AST_EXPR
} NodeType;
typedef struct AstNumNode AstNumNode;
typedef struct AstExprNode AstExprNode;
typedef struct AstNode {
NodeType type;
union {
AstNumNode* num;
AstExprNode* expr;
} actual;
} AstNode;
struct AstExprNode {
AstNode* left;
AstNode* right;
};
struct AstNumNode {
int value;
};
当然,我仍然需要编写如下方法:
void ast_node_print(AstNode* node, int depth); // switch on node->type and select one of the below methods based on that type
void ast_num_print(AstNumNode* node, int depth);
void ast_expr_print(AstExprNode* node, int depth);
我认为它比访问者模式简单得多。
但是,当我创建这些节点时,执行以下操作可能会有点繁琐:
AstNode* numNode = malloc(sizeof(AstNode));
numNode->type = AST_NUM;
numNode->actual.num = malloc(sizeof(AstNumNode));
numNode->actual.num->value = 10;
我能看到的最后一个缺点是空间。由于联合,每个AstNode
将占用相同的空间量,而不管它 Package 了什么“子节点”。当编译大型程序时,我可以看到这成为一个问题。
2条答案
按热度按时间n3h0vuf21#
我能看到的最后一个缺点是空间,由于联合,每个AstNode将占用相同的空间量,而不管它 Package 的是哪个“子节点
在C中,使用flexible array member,以便根据需要调整最后一个成员的内存大小。
...然后分配到所需的大小
这将旧代码中完成的2个分配滚动到1个。
然而,在没有看到更大背景的情况下,还不清楚这是否值得。
真正的目标
OP似乎想减少复杂性/代码和对象内存空间。这些通常与地球其他冲突。决定:选择balance或选择one
9bfwbjaz2#
我已经尝试了建议的方法。最后,随着代码的发展,联盟变得如此之大,很难保持代码的可读性。此外,还有一些样板文件来为每种节点启动正确的成员。
我也认为访问者模式是冗长的。我最后使用的是一个名为AstNode的基类,它有一个种类(你的NodeType类型)。每个扩展AstNode的类都设置了适当的种类。这被认为是不好的,因为我做了很多指针转换,但最终对我来说比访问者方法更理智。
虽然没有使用访问者模式,但我最终编写了许多类似于访问者的方法,但没有样板(相同的函数适用于许多节点,并进行了一些类型转换)。
在AstNode中有一个类也帮助我跟踪我还没有实现的用例,我可以做一个切换用例,并设置一个带有警告消息的默认值,以提醒我一个已实现的用例。
我不知道你的语言现在在哪里。我的是在中间代码生成步骤,我如何访问这里的Ast方法帮助我驱动“final”结构。例如,我想轻松访问标识符的类型、符号、字节大小等。所以我在AstIdentifier中添加了一些指针,如果我使用联合方法,它将对我的跟踪能力来说太大了。所以不用传递符号表上下文或者其他什么,我可以使用id.get_type(),id.get_size(),id.get_address()等等。
最后,我的建议是:选择对你来说比较容易的方法。2做这件事真的没有对错之分。3我花了一些时间来适应这种方法并感到舒服。
如果可以的话,请阅读Terence Parr的《语言实现模式》一书。如果我没记错的话,第4章讨论了构建AST的不同方法,以及每种方法的优缺点,包括您建议的方法。