私の知る限り、書き換えルールの構文では、暫定的なスニペットが示唆するように値を直接割り当てることはできません。これは、パーサーがツリー/ノードのどの部分に値を追加する必要があるかを実際には知らないという事実に一部起因しています。
ただし、ANTLRで生成されたASTの優れた機能の1つは、パーサーがノードのタイプについて何も想定していないことです。新しいノードのファクトリとして、またツリー構造のナビゲーターとして機能するTreeAdapatorを実装する必要があります。したがって、以下で説明するように、ノードで必要になる可能性のある情報を詰め込むことができます。
ANTLRは、デフォルトのツリーノード実装であるCommonTreeを提供します。ほとんどの場合(現在の状況のように)、必要なのは単に
- いくつかのカスタムフィールドを追加してCommonTreeをサブクラス化します
- CommonTreeAdaptorをサブクラス化して、create()メソッド、つまり新しいノードを生成する方法をオーバーライドします。
しかし、奇妙なグラフ構造などのために、まったく新しいタイプのノードを作成することもできます。当面の場合、以下で十分です(これがJavaでない場合は、特定のターゲット言語に適応します)
import org.antlr.runtime.tree.*;
import org.antlr.runtime.Token;
public class NodeWithScope extends CommonTree {
/* Just declare the extra fields for the node */
public ArrayList symbols;
public string name;
public object whatever_else;
public NodeWithScope (Token t) {
super(t);
}
}
/* TreeAdaptor: we just need to override create method */
class NodeWithScopeAdaptor extends CommonTreeAdaptor {
public Object create(Token standardPayload) {
return new NodeWithScope(standardPayload);
}
}
次に、解析プロセスの開始方法を少し変更して、ANTLR(またはANTLRで生成されたパーサー)がCommnTreeではなくNodeWithScopeAdaptorを使用することを認識できるようにする必要があります。
(以下のステップ4.1、残りはかなり標準的なANTLRテストリグの場合)
// ***** Typical ANTLR pipe rig *****
// ** 1. input stream
ANTLRInputStream input = new ANTLRInputStream(my_input_file);
// ** 2, Lexer
MyGrammarLexer lexer = new MyGrammarLexer(input);
// ** 3. token stream produced by lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// ** 4. Parser
MyGrammarParser parser = new MyGrammarParser(tokens);
// 4.1 !!! Specify the TreeAdapter
NodeWithScopeAdaptor adaptor = new NodeWithScopeAdaptor();
parser.setTreeAdaptor(adaptor); // use my adaptor
// ** 5. Start process by invoking the root rule
r = parser.MyTopRule();
// ** 6. AST tree
NodeWithScope t = (NodeWithScope)r.getTree();
// ** 7. etc. parse the tree or do whatever is needed on it.
最後に、文法を次のようなものに適合させる必要があります
([現在のルールの]ノードは@afterセクションでのみ使用可能であることに注意してください。ただし、文法レベルからトークン属性やその他のコンテキスト変数を参照する場合があります。 、通常の$ rule.atrribute表記を使用)
composite_instruction
scope JScope;
@init {
$JScope::symbols = new ArrayList();
$JScope::name = "level "+ $JScope.size();
}
@after {
($composite_instruction.tree).symbols = $JScope::symbols;
($composite_instruction.tree).name = $JScope::name;
($composite_instruction.tree).whatever_else
= new myFancyObject($x.Text, $y.line, whatever, blah);
}
: '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*)
;