ツリーは通常、その子へのポインターを含む構造体として表され、node
ノード型を格納するメンバーを持っているか、実際の型を導出できるように特定のクラスになっています (つまり、算術式を保持している場合は、 if ステートメント、ループなど)。
あなたが言及したように、簡単な例は確かにif
ステートメントです。そのためには、次のようにします (疑似 C が続きます)。
enum AST_Node {
Node_if,
Node_and,
Node_or,
Node_not,
Node_equal,
Node_less,
// etc., other node types follow
};
struct AST {
struct AST *children[MAX_CHILDREN]; // don't do this
enum AST_Node node;
};
struct AST *parse_if_statement()
{
// expect tokens in order
expect("if");
// parse condition
expect("(");
struct AST *condition = parse_expression();
expect(")");
// parse two child statements
struct AST *then_branch = parse_statement();
struct AST *else_branch = NULL;
if (accept("else")) {
else_branch = parse_statement();
}
// create AST, fill in children
struct AST *if_statement = new_AST_node(Node_if);
if_statement->children[0] = condition;
if_statement->children[1] = then_branch;
if_statement->children[2] = else_branch;
return if_statement;
}
したがって、基本的には、永続的な字句要素 (「if」、条件を囲む括弧など) を期待/受け入れるだけで、サブツリー (条件と 2 つの分岐) の解析を適切なパーサー関数に渡します。
これがツリーをたどる方法です。基本的には深さ優先のウォークを行い、各子を順番にコンパイルまたは解釈します。次に、現在解釈/コンパイルされているサブツリーのノード タイプが意味する追加のセマンティクスを追加します。
Value *interpret_if_statement(struct AST *ast)
{
assert(ast->node == Node_if);
struct AST *condition = ast->children[0];
struct AST *then_branch = ast->children[1];
struct AST *else_branch = ast->children[2];
// evaluate condition
Value *condval = interpret_expression(condition);
if (condval->bool_value == TRUE) {
// if condition is true, interpret "then" branch
return interpret_statement(then_branch);
} else if (else_branch != NULL) {
// otherwise interpret "else" branch, if any
return interpret_statement(else_branch);
} else {
return NULL;
}
}