ツリーの構築中にこの再配置を実行できますか、それともツリーの文法を書く必要がありますか?
どちらも可能ですが、トークンの解析中にノードをグループ化することをお勧めします。
そのグループノードを作成したツリー書き換え文法には満足していません。これらの文法は、グループ化可能な各ノードがどこにあるかを再発見する必要があるためです。したがって、グループ化が必要です。トークンパーサーは通常の処理中にそのすべてのデータにアクセスし、ツリー文法は、トークンパーサーがすでにトークンの入力をウォークしたのとまったく同じように、それらのノードのツリーをウォークすることになります。グループ化のためだけの場合、ツリーパーサーは面倒な価値があるとは思いません。
とにかく、パーサーでのグループ化の管理は、生成後にノードdecl
とassign
ノードを保存し、グループ化レベルが発生したときにノードを再びプッシュすることになります。これが簡単な例です。
Declarative.g
grammar Declarative;
options {
output = AST;
}
tokens {
PROGRAM; DECLARATIONS; ASSIGNMENTS;
}
@parser::header {
import java.util.ArrayList;
}
@members {
private ArrayList<Object> assigns = new ArrayList<Object>();
private ArrayList<Object> decls = new ArrayList<Object>();
private Object createTree(int ttype, ArrayList<Object> children) {
Object tree = adaptor.create(ttype, tokenNames[ttype]);
for (Object child : children){
adaptor.addChild(tree, child);
}
return tree;
}
}
compilationUnit : statement* EOF -> ^(PROGRAM {createTree(DECLARATIONS, decls)} {createTree(ASSIGNMENTS, assigns)});
statement : decl {decls.add($decl.tree);}
| assign {assigns.add($assign.tree);}
;
decl : DECL^ ID;
assign : ASSIGN^ ID INT;
DECL : 'decl';
ASSIGN : 'assign';
ID : ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z')*;
INT : ('0'..'9')+;
WS : (' '|'\t'|'\f'|'\n'|'\r'){skip();};
各decl
ノードは、リストstatement
内のルールによって保存され、各ノードについても同様に保存されます。decls
assign
メソッドcreateTree
は、パーサーを使用しTreeAdaptor
てグループノードを構築し、それらにデータを入力します。
CommonTree tree = (CommonTree) adaptor.create(ttype, tokenNames[ttype]);
for (Object child : children){
adaptor.addChild(tree, child);
}
return tree;
のプロダクションcompilationUnit
は^(PROGRAM {createTree(DECLARATIONS, decls)} {createTree(ASSIGNMENTS, assigns)})
、にグループ化ノードを追加するPROGRAM
です。メソッドcreateTree
は、グループ化ノードとその子を一度に構築するために使用されます。
ANTLRにすべてをまとめてもらうには難しい方法があるかもしれませんが、これは機能し、かなり自明です。
したがって、この入力が与えられます...
decl x
assign y 2
assign x 1
decl y
...上記の文法用に生成されたトークンパーサーは、このツリーを出力として生成します。
(PROGRAM
(DECLARATIONS
(decl x)
(decl y))
(ASSIGNMENTS
(assign y 2)
(assign x 1)))