我有很多结构,看起来像:
typedef struct ast_function_node
{
int node_type;
ast_node* arguments;
symbol* sym;
} ast_function_node;
typedef struct ast_while_node
{
int node_type;
ast_node* condition;
ast_node* while_branch;
} ast_while_node;
typedef struct ast_assignment_node
{
int node_type;
symbol* sym;
ast_node* value;
} ast_assignment_node;
typedef struct ast_number_node
{
int node_type;
double value;
} ast_number_node;
typedef struct ast_string_node
{
int node_type;
char* value;
} ast_string_node;
etc...
一个基础结构:
typedef struct // Basic AST node
{
int node_type;
struct ast_node* left;
struct ast_node* right;
} ast_node;
我可以很容易地填充这个AST,但是当涉及到遍历它时,我陷入了类型转换的困境。如果我想访问每个节点,查看其类型然后相应地做一些事情,这样做的最佳方法是什么?只是将它投射到ast_node
的基本节点当然不会这样做。
我在C中这样做的方法是使用带有struct
成员的union
:
typedef struct ast_function
{
ast_node* arguments;
symbol* sym;
} ast_function;
typedef struct ast_while
{
ast_node* condition;
ast_node* while_branch;
} ast_while;
typedef struct ast_assignment
{
symbol* sym;
ast_node* value;
} ast_assignment;
/* Etc. */
typedef struct ast_node {
int node_type;
/* See anonymous unions in any C reference */
union {
ast_function function_data;
ast_while while_data;
ast_assignment assignment_data;
/* Etc. */
};
}
那你根本不需要演员:
switch (node->node_type) {
case AST_FUNCTION:
handle_function(&node->function_data);
break;
/* Etc. */
}
如果你使node_type
成为enum
而不是int
,编译器将能够在你的switch
声明中错过一个可能性时发出警告。