この質問は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;
};
あなたの質問はどのように横断するのですか?この場合の走査は、Visiting Nodesと呼ばれます。各ノードにアクセスするには、各ノードタイプを使用して、各構文ノードのデータを評価する方法を決定する必要があります。
次に、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;
};
呼び出されたノードビジターの印刷関数に戻り、次のCコードを追加することでAST_PrintNode
、if
ステートメント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;
それと同じくらい簡単!結論として、構文ツリーは、ツリーとそのデータ自体のタグ付き結合のツリーにすぎません!