Это зависит от того, что вы хотите сделать над этим деревом.
Я обычно реализую его, создавая конкретный узел для каждого вида операций, который мне понадобится, например,
ASTBinaryOperation implements ASTNode
{
ASTNode left, right;
Operator op;
Result visit()
{
Result lr = left.visit();
Result rr = right.visit();
return op.apply(lr, rr);
}
}
для классического узла двоичного оператора, хотя я бы использовал ArrayList
, например, для объявлений:
ASTDecl implements ASTNode
{
String name;
Type type;
Value value;
}
ASTDecls implements ASTNode
{
ArrayList<ASTDecl> declarations;
}
, который создается синтаксическим анализатором.Таким образом, корневой узел будет выглядеть примерно так:
ASTRoot {
ASTDecls declarations;
ASTFunctions functions;
}
ASTFunctions {
ASTDecls args;
ASTBody body;
..
}
ASTBody {
ArrayList<ASTStatement> statements;
...
}
и т. Д.
Конечно, это зависит от того, что вы захотите сделать, я использовал этот подход, чтобы посетить AST для генерациипромежуточный код, рекурсивно посещая дерево ... но сохраняя что-либо в ArrayList
, вы потеряете специфическое поведение и значение одного ASTNode
.