3

宣言やその他のステートメントの順序が重要でない宣言型文法を書き込もうとしています。ただし、構文解析では、文法に順序付けられた方法でツリーを出力させたいと思います。decl言語が宣言( )と割り当て()で構成されているとしましょうassign。例は次のとおりです。

decl x
assign y 2
assign x 1
decl y

1つのサブツリーにすべての宣言があり、別のサブツリーにすべての割り当てがあるツリーでプログラムを表現したいと思います。上記の例では、次のようになります。

(PROGRAM
    (DECLARATIONS x y)
    (ASSIGNMENTS
        (y 2)
        (x 1)))

ツリーの構築中にこの再配置を実行できますか、それともツリーの文法を書く必要がありますか?

4

2 に答える 2

3

私はここで他のものよりも簡単な答えがあると思います:

token { DECLS; ASSIGNS; }

prog: (d+=decl | a+=assign)* EOF -> ^(DECLS $d*) ^(ASSIGNS $a*) ;

...

もちろん、これは好きなだけルールに適合させることができます。

ただし、これを行う必要がありますか?パーサーでDECL命令のシンボルテーブルを作成してから、ツリーウォークで確認できるASSIGNのASTのみを作成してみませんか。

ジム

于 2012-12-11T06:49:07.397 に答える
2

ツリーの構築中にこの再配置を実行できますか、それともツリーの文法を書く必要がありますか?

どちらも可能ですが、トークンの解析中にノードをグループ化することをお勧めします。

そのグループノードを作成したツリー書き換え文法には満足していません。これらの文法は、グループ化可能な各ノードがどこにあるかを再発見する必要があるためです。したがって、グループ化が必要です。トークンパーサーは通常の処理中にそのすべてのデータにアクセスし、ツリー文法は、トークンパーサーがすでにトークンの入力をウォークしたのとまったく同じように、それらのノードのツリーをウォークすることになります。グループ化のためだけの場合、ツリーパーサーは面倒な価値があるとは思いません。

とにかく、パーサーでのグループ化の管理は、生成後にノードdeclassignノードを保存し、グループ化レベルが発生したときにノードを再びプッシュすることになります。これが簡単な例です。

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内のルールによって保存され、各ノードについても同様に保存されます。declsassign

メソッド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)))
于 2012-12-11T05:48:38.093 に答える