2010-11-17 40 views
0

我需要爲具有前向引用的語言創建語法。我認爲最簡單的方法是在生成的AST上進行幾次傳遞,但我需要一種方法在樹中存儲符號信息。ANTLR前向引用

現在我的分析器正確地生成一個AST並計算變量和函數定義的範圍。問題是,我不知道如何將範圍信息保存到樹中。

片段我的語法:

composite_instruction 
scope JScope; 
@init { 
    $JScope::symbols = new ArrayList(); 
    $JScope::name = "level "+ $JScope.size(); 
} 
@after { 
    System.out.println("code block scope " +$JScope::name + " = " + $JScope::symbols); 
} 
    : '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*) 
    ; 

我願把目前的範圍參考成一棵樹,是這樣的:

: '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction* {$JScope::symbols}) 

它甚至有可能?有沒有其他方法可以將當前範圍存儲在生成的樹中?我可以在樹語法中生成範圍信息,但它不會改變任何東西,因爲我仍然需要將它存儲在樹上的第二遍。

+0

不[此Q&A](HTTP:/ /stackoverflow.com/questions/4075510/how-to-implement-a-function-call-with-antlr-so-那可以稱爲 - 甚至在之前)幫助? – 2010-11-18 00:14:00

回答

2

據我所知,重寫規則的語法不允許直接分配值作爲您的暫定片段建議。這部分是由於解析器不會真正知道應將值添加到樹/節點的哪一部分。

然而,ANTLR生成的AST的一個很酷的功能是解析器不會對節點的類型做任何假設。只需要實現一個TreeAdapator,它可以作爲新節點的工廠,也可以作爲樹結構的導航器。因此,可以填充節點中可能需要的任何信息,如下所述。

ANTLR提供了一個默認的樹節點實現,CommonTree,在大多數情況下(如在當時的情況),我們只是增加了一些自定義字段給它

  • 需要

    • 子CommonTree子類CommonTreeAdaptor覆蓋它的create()方法,即它產生新節點的方式。

    但也可以創建一種新型節點altogher,對於一些奇怪的圖形結構或whatnot。手頭的情況下,下面應該是足夠了(爲適應特定目標語言,如果這不是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生成的解析器)知道使用NodeWithScopeAdaptor而不是CommnTree。
    (下面的步驟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*) 
        ; 
    
  • +0

    這可能是我正在尋找的東西,但我決定在解析過程中構建自己的樹,然後用範圍填充它並執行其他檢查。謝謝! – bialpio 2010-12-18 17:48:08