ฉันรู้ว่าคำถามนี้มีอายุ 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 เข้ากับโครงสร้างโหนดเดิมของเรา โปรดจำไว้ว่าหากข้อความเหล่านั้นสามารถมีได้หากข้อความดังนั้นการเรียกซ้ำภายในระบบโหนดของเราจึงอาจเกิดขึ้นได้ คำสั่งอื่นเป็นทางเลือกดังนั้น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
คำสั่ง AST สร้างโดยการเพิ่มรหัส C นี้:
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;
ง่ายเหมือนที่! โดยสรุปต้นไม้ Syntax ไม่ได้เป็นอะไรมากไปกว่าแผนผังของสหภาพที่ติดแท็กของต้นไม้และข้อมูลของมันเอง!