我知道这个问题已经4岁多了,但是我觉得我应该添加一个更详细的答案。
抽象语法树的创建与其他树没有什么不同;在这种情况下,更正确的说法是语法树节点的节点数量各不相同。
一个例子是二进制表达式,例如:1 + 2
一个简单的表达式,它将创建一个单个的根节点,该节点包含一个左右节点,该节点保存有关数字的数据。在C语言中,它看起来像
struct ASTNode;
union SyntaxNode {
int64_t llVal;
uint64_t ullVal;
struct {
struct ASTNode *left, *right;
} BinaryExpr;
};
enum SyntaxNodeType {
AST_IntVal, AST_Add, AST_Sub, AST_Mul, AST_Div, AST_Mod,
};
struct ASTNode {
union SyntaxNode *Data;
enum SyntaxNodeType Type;
};
您的问题还在于如何遍历?在这种情况下,遍历称为“ 访问节点”。访问每个节点要求您使用每种节点类型来确定如何评估每个语法节点的数据。
这是C语言中的另一个示例,我只打印了每个节点的内容:
void AST_PrintNode(const ASTNode *node)
{
if( !node )
return;
char *opername = NULL;
switch( node->Type ) {
case AST_IntVal:
printf("AST Integer Literal - %lli\n", node->Data->llVal);
break;
case AST_Add:
if( !opername )
opername = "+";
case AST_Sub:
if( !opername )
opername = "-";
case AST_Mul:
if( !opername )
opername = "*";
case AST_Div:
if( !opername )
opername = "/";
case AST_Mod:
if( !opername )
opername = "%";
printf("AST Binary Expr - Oper: \'%s\' Left:\'%p\' | Right:\'%p\'\n", opername, node->Data->BinaryExpr.left, node->Data->BinaryExpr.right);
AST_PrintNode(node->Data->BinaryExpr.left); // NOTE: Recursively Visit each node.
AST_PrintNode(node->Data->BinaryExpr.right);
break;
}
}
请注意,函数如何根据我们正在处理的节点类型来递归地访问每个节点。
让我们添加一个更复杂的示例,一个if
语句构造!回想一下if语句还可以具有可选的else子句。让我们将if-else语句添加到我们的原始节点结构中。请记住,if语句本身也可以具有if语句,因此在节点系统中可能会发生某种递归。其他语句是可选的,因此该elsestmt
字段可以为NULL,递归访问者函数可以忽略该字段。
struct ASTNode;
union SyntaxNode {
int64_t llVal;
uint64_t ullVal;
struct {
struct ASTNode *left, *right;
} BinaryExpr;
struct {
struct ASTNode *expr, *stmt, *elsestmt;
} IfStmt;
};
enum SyntaxNodeType {
AST_IntVal, AST_Add, AST_Sub, AST_Mul, AST_Div, AST_Mod, AST_IfStmt, AST_ElseStmt, AST_Stmt
};
struct ASTNode {
union SyntaxNode *Data;
enum SyntaxNodeType Type;
};
回到称为的节点访问者打印函数中AST_PrintNode
,我们可以if
通过添加以下C代码来容纳语句AST构造:
case AST_IfStmt:
puts("AST If Statement\n");
AST_PrintNode(node->Data->IfStmt.expr);
AST_PrintNode(node->Data->IfStmt.stmt);
AST_PrintNode(node->Data->IfStmt.elsestmt);
break;
就如此容易!总之,语法树只不过是带有标记的树及其数据本身的并集的树!